Questions tagged «design-patterns»

设计模式是解决软件设计中常见问题的通用可重用解决方案。

1
胶水或管理课程什么时候做得太多?
我倾向于建立集中的类来管理设计中的其他类。它本身并不存储所有内容,但是大多数数据请求将首先发送给“经理”。在寻找这个问题的答案时,我注意到术语“上帝对象”。可以理解,维基百科将其列为反模式。 合法的胶水类或模块之间的界限在哪里,该胶水类或模块从各处传递数据和消息,而该胶粘类或模块做得太多呢?

4
领域驱动设计中的重构
已关闭。这个问题需要细节或说明。它当前不接受答案。 想改善这个问题吗?添加细节并通过编辑此帖子来澄清问题。 6年前关闭。 我刚刚开始从事一个项目,我们正在使用领域驱动的设计(由Eric Evans在“ 领域驱动的设计:解决软件核心中的复杂性”中定义。我相信我们的项目肯定是该设计的候选人就像埃文斯在书中描述的那样。 我在不断重构的想法中挣扎。 我知道在任何项目中重构都是必不可少的,随着软件的改变,重构将不可避免地发生。但是,根据我的经验,重构是在开发团队的需求发生变化时发生的,而不是对领域变化的理解(Evans称之为“重构以获得更大的洞察力”)。我最关心的是对领域模型的理解方面的突破。我知道进行小的更改,但是如果需要对模型进行较大的更改怎么办? 在说服更清晰的域模型之后,应该说服自己(和其他人)重构的有效方法是什么?毕竟,为了改善代码的组织或性能而进行的重构可能与无处不在的语言代码的表达方式完全不同。有时似乎没有足够的时间进行重构。 幸运的是,SCRUM使它可以进行重构。SCRUM的迭代性质使其易于构建一小块并进行更改。但是随着时间的流逝,该片段会变大,如果您在该片段太大而又难以更改时又取得突破,该怎么办? 是否有人从事采用领域驱动设计的项目?如果是这样,那么对此有所了解将是很棒的。我特别想听听一些成功的故事,因为DDD似乎很难解决。 谢谢!

2
函数式编程如何处理从多个位置引用同一对象的情况?
我正在阅读和听到,人们(也在此站点上)经常赞美函数式编程范例,强调使所有内容保持不变是多么好的。值得注意的是,人们甚至在传统的命令式OO语言(例如C#,Java或C ++)中也提出了这种方法,不仅是在像Haskell这样的纯函数式语言中,这种语言迫使程序员这样做。 我觉得很难理解,因为我发现可变性和副作用...很方便。但是,考虑到人们当前如何谴责副作用并认为是在可能的情况下消除它们的一种好习惯,我相信如果我想成为一名合格的程序员,我必须让我的乔妮开始对这种范例有一些更好的了解...因此,我的问。 当我发现功能范式存在问题时,一个地方就是自然地从多个地方引用一个对象。让我用两个例子来描述它。 第一个例子是我打算在业余时间制作的C#游戏。这是一种基于回合制的网络游戏,其中两个玩家都有4个怪物组成的团队,并且可以将一个怪物从其团队中移到战场上,在那里它将面对对方玩家发送的怪物。玩家还可以从战场上召回怪物,并用其团队中的另一个怪物代替它们(类似于口袋妖怪)。 在这种情况下,可以从至少2个地方自然引用单个怪物:玩家的团队和战场,其中引用了两个“活动”怪物。 现在,让我们考虑一个怪物被击中并失去20点生命值时的情况。在命令式范式的括号内,我修改了此怪物的health字段以反映此更改-这就是我现在正在做的。但是,这使Monster类可变且相关的函数(方法)不纯净,我认为到目前为止,这仍被认为是一种不好的做法。 即使我允许自己以低于理想状态的方式编写游戏代码,以便希望在将来的某个时候完成游戏,但我还是想知道并理解它应该如何写得正确。因此:如果这是设计缺陷,如何解决? 就我所知,在函数式中,我将对此Monster对象进行复制,使其与旧对象相同,除了该字段。并且该方法suffer_hit将返回此新对象,而不是就地修改旧对象。然后,我同样会复制Battlefield对象,并保持其所有字段相同(除了该怪物)。 这至少有两个困难: 层次结构可以比Just- Battlefield>的简化示例更深入Monster。我必须对所有字段(除了一个字段)进行这种复制,并在此层次结构中一直返回一个新对象。这将是样板代码,我发现这很烦人,特别是因为功能编程应该减少样板代码。 但是,一个更为严重的问题是,这将导致数据不同步。野外活动的怪物的生命值会降低。但是,从其控制者那里引用的同一个怪物Team不会。如果我改用命令式风格,那么对数据的每次修改都可以在所有其他代码位置立即看到,在这种情况下,我发现它真的很方便- 但是我得到东西的方式正是人们所说的势在必行! 现在,可以通过Team每次攻击之后的旅程来解决此问题。这是额外的工作。但是,如果以后突然可以从更多地方引用怪物,该怎么办?例如,如果我具有一种能力,例如,让一个怪物专注于另一个不一定在场上的怪物(我实际上正在考虑这种能力)怎么办?我肯定会记得在每次攻击后立即进行一次聚焦怪物的旅程吗?这似乎是一个定时炸弹,随着代码变得越来越复杂,它会爆炸,所以我认为这是没有解决方案的。 当我遇到相同的问题时,从第二个示例中得出一个更好的解决方案的想法。在学术界,我们被告知要在Haskell中编写我们自己设计的语言的口译员。(这也是我被迫开始了解FP是什么的方式)。当我实现闭包时出现了问题。现在可以再次从多个位置引用同一作用域:通过保存该作用域的变量以及任何嵌套作用域的父作用域!显然,如果通过指向该范围的任何引用对该范围进行了更改,则此更改也必须通过所有其他引用可见。 我提出的解决方案是为每个范围分配一个ID,并在Statemonad中保存所有范围的中央字典。现在,变量将仅保留它们绑定到的作用域的ID,而不是作用域本身,并且嵌套作用域还将保留其父作用域的ID。 我猜想在我的怪物战斗游戏中可以尝试相同的方法。相反,它们拥有保存在中央怪物词典中的怪物ID。 但是,我再次看到这种方法存在问题,使我无法毫不犹豫地接受它作为解决问题的方法: 它再次是样板代码的来源。它使单线必然变成三线:以前对单个字段进行单行就地修改现在需要(a)从中央字典中检索对象(b)进行更改(c)保存新对象到中央字典。同样,持有对象和中央字典的id而不是拥有引用会增加复杂性。因为FP的广告是为了减少复杂性和样板代码,所以这暗示我做错了。 我还打算写一个似乎更严重的第二个问题:这种方法引入了内存泄漏。无法访问的对象通常将被垃圾回收。但是,即使没有可访问的对象都引用此特定ID,也无法对中央词典中保存的对象进行垃圾回收。尽管从理论上讲,仔细的编程可以避免内存泄漏(一旦不再需要,我们可以小心地从中央字典中手动删除每个对象),但是这很容易出错,并且FP广告宣传增加了程序的正确性,因此这可能再次不是正确的方法。 但是,我及时发现它似乎是一个已解决的问题。Java提供WeakHashMap了可用于解决此问题的方法。C#提供了类似的功能- ConditionalWeakTable尽管根据文档,它是供编译器使用的。在Haskell中,我们有System.Mem.Weak。 存储此类词典是解决此问题的正确功能解决方案,还是我看不到更简单的解决方案?我想象这样的词典的数量很容易增长,而且非常糟糕。因此,如果这些字典区域也应该是不可变的,这可能意味着很多参数传递,或者在支持该功能的语言中,表示单子计算,因为字典将以单子形式保存(但是我再次将其读为纯函数式)语言,尽可能少的代码应该是monadic,而这个字典解决方案会将几乎所有代码都放在Statemonad内;这再次使我怀疑这是否是正确的解决方案。) 经过一番考虑之后,我想我会再问一个问题:构建这样的词典能获得什么?许多专家认为,命令式编程的错误之处在于某些对象的更改会传播到其他代码段。为了解决这个问题,对象应该是不可变的-正是出于这个原因,如果我正确理解的话,对它们所做的更改应该在其他地方不可见。但是现在,我担心对过期数据进行操作的其他代码段,因此发明了中央字典,以便……将某些代码段中的更改再次传播到其他代码段中!因此,我们不是回到带有所有假定缺点的命令式样式,而是增加了复杂性吗?

4
对某些用户隐藏/禁用功能
可以说我有该应用程序的免费和付费版本。付费版本是免费版本在用户可用功能方面的超集,这意味着付费版本将具有免费应用程序的所有功能以及其他功能。 是否存在根据启动时加载的标志(例如,免费/付费)来切换功能可用性的模式? 我不喜欢到处都有以下代码块的想法: if(isFreeVersion){ // ... } else { // ... } 每个版本都没有2个单独的git分支是不可行的,因为这意味着要维护2个(或更多)代码源,这在一般情况下似乎不切实际,并在此处进行了更多讨论:在Version Control中从同一代码库维护两个单独的软件版本。 有办法做到这一点,同时仍然只有一个代码库,并且不会用检查自由/已付费标志的条件语句来乱扔代码吗? 我敢肯定这已经被讨论过很多次了,并且我肯定有一些解决这个问题的模式,但是我只是找不到它。 我们使用Android / Java。

3
如何重构具有多个切换案例的应用程序?
我有一个应用程序,它使用整数作为输入,并基于输入调用不同类的静态方法。每次添加新数字时,我们需要添加另一种情况,并调用不同类的不同静态方法。交换机中现在有50个案例,每当我需要添加另一个案例时,我都会发抖。有一个更好的方法吗。 我做了一些思考,想到了这个主意。我使用策略模式。我没有交换条件,而是有一个策略对象映射,键为输入整数。调用方法后,它将查找对象并为该对象调用通用方法。这样,我可以避免使用switch case结构。 你怎么看?

3
基类中的抽象属性,强制程序员对其进行定义
我正在使用嵌入式设备的状态模式进行编码。我有一个称为State的基类/抽象类,然后每个离散(具体)状态类都实现了抽象State类。 在状态类中,我有几种抽象方法。如果我不在离散(具体)类中实现抽象方法,Visual Studio将给出如下错误: ...错误1'myConcreteState'未实现继承的抽象成员'myAbstractState' 现在:我正在尝试为每个名为StateName的州创建String属性。每当创建新的具体类时,都需要定义StateName。如果不使用VS,我希望VS抛出错误。有没有简单的方法可以做到这一点? 我已经在抽象/基类中尝试过此操作: public abstract string StateName { get; set; } 但是我不需要在每个州中实现Get和Set方法。 修订的问题:在理想情况下,将要求每个状态类都具有StateName定义并从抽象基类继承。 StateName = "MyState1"; //or whatever the state's name is 如果缺少该语句,则Visual Studio将生成如上所述的错误。这可能吗?如果可以,怎么办?

1
在delphi Pascal中实现MVVM和MVC的最佳实践
我是一个Delphi Pascal程序员,我使用最新的Embarcadero delphi XE,并且想利用诸如模型视图控制器和模型视图视图模型之类的设计模式。 但是,关于在Pascal上执行此操作的最佳做​​法,在网络上似乎没有很多。我可以找到的大多数示例都在C#中,并且某些语言功能在pascal中不存在,这意味着我可能必须找到实现这些功能的方法。 我正在尝试从此处修改本文的代码 我将列出我面临的问题 可空类型 Pascal不像C#那样具有可为空的类型,因此我创建了自己的类型。 TNullable<T> = record strict private fHasValue : boolean; fValue : T; function GetValue:T; procedure SetValue(newValue : T); public property HasValue : boolean read fHasValue; property Value : T read GetValue write SetValue; procedure SetToNull; end; 在实施部分 function TNullable<T>.GetValue:T; begin if fHasValue …

2
要存储库还是不存储库
当我第一次了解域驱动设计时,我还被介绍到了存储库和工作单元模式,这些存储模式和工作单元曾经看起来像是那些酷炫的孩子向数据库发送SQL查询(例如穴居人)的最佳选择。我对这个话题的了解越深,我越了解到它们似乎不再是必需的了,因为EF和NHibernate之类的ORM将工作单元和存储库都实现到一个称为会话或上下文的API中。 现在我不确定该怎么办。是否存储库。我真的很理解这样的论点,即这样的泄漏抽象只会使事情复杂化,而绝对没有增加任何可以简化数据访问的内容,但是,将我的应用程序的各个方面都耦合到例如Entity Framework的感觉并不正确。通常,我遵循一些简单的准则: 域层是系统的核心,包含实体,服务,存储库... 基础结构层提供基础结构领域的域接口的实现,例如文件,数据库,协议。 应用程序层承载一个组合根,该根将所有事物连接起来并进行编排。 我的解决方案通常如下所示: Domain.Module1 Domain.Module2 IModule2Repo IModule2Service Module2 Infrastructure.Persistence Repositories EntityFrameworkRepositoryBase MyApp Boostrapper -> inject EntityFrameworkRepositoryBase into IRepository etc. 我使用a保持域层整洁,IRepository<'T>这也是一个域问题,不依赖于任何其他告诉我如何访问数据的内容。当我现在要实现IModule2Service需要数据访问的具体实现时,我将不得不注入DbContext并将其直接耦合到基础架构层。(要进入Visual Studio项目,由于循环依赖关系,最终可能会非常棘手!) 另外有什么可以到其他托管和作品fucktons?CQRS?如何抽象一个纯粹的基础架构?

2
如Head First设计模式的Duck示例所示,上下文继承与策略模式无关吗?
在Head First Design Patterns中,它通过使用Duck示例讲授策略模式,其中可以在运行时为Duck的不同子类分配特定的行为。根据我的理解,策略模式的目的是在运行时更改单个对象的行为,但是他们使用Duck的继承来更改各种Duck的行为。 关联? Duck的上下文继承是否与策略模式无关,或者是改变Duck类型并改变其行为也是采用策略模式的充分理由吗?您需要同时改变两者的情况是否构成使用策略模式的充分理由?他们为何将其作为策略模式示例? 一个简单的例子 我是否可以仅使用Duck类(没有派生类)来进一步简化此示例?然后,在实现一个鸭子对象时,可以根据不依赖于其自身对象类型的某些情况为其分配不同的行为。例如:FlyBehavior根据天气而变化或QuackBehavior根据一天中的时间或鸭子的饥饿程度而变化。我意识到这将解决与书中提出的问题不同的问题,但是我正在寻找的是可以依靠的相关策略模式示例。 我上面的例子也会构成战略模式吗? 编辑: 我成功找到了两个更简单的策略模式示例,它们更严格地只是没有上下文继承的策略模式:Hunter.java和Solver.py。

4
允许库分离的多态行为设计模式
假设我有一个Item类的层次结构:Rectangle, Circle, Triangle。我希望能够绘制它们,所以我的第一种可能是Draw()向每个虚拟方法添加一个虚拟方法: class Item { public: virtual ~Item(); virtual void Draw() =0; }; 但是,我想将绘图功能拆分到单独的Draw库中,而Core库仅包含基本表示形式。我可以想到几种可能性: 1-A DrawManager接受Items 的列表,必须使用它dynamic_cast<>来确定要做什么: class DrawManager { void draw(ItemList& items) { FOREACH(Item* item, items) { if (dynamic_cast<Rectangle*>(item)) { drawRectangle(); } else if (dynamic_cast<Circle*>(item)) { drawCircle(); } .... } } }; 这不是理想的选择,因为它依赖于RTTI并迫使一个类了解层次结构中的所有项。 2-另一种方法是将绘图责任推迟到一个ItemDrawer层次结构(RectangleDrawer,等): class Item { virtual …

3
我如何才能有意识地实践设计模式和重构?[关闭]
关闭。这个问题是题外话。它当前不接受答案。 想改善这个问题吗? 更新问题,使它成为软件工程堆栈交换的主题。 4年前关闭。 我正在阅读《重构为模式》一书,想知道如何获得机会练习这些技能,因为如果不认真尝试重构和使用模式的新方法,我的技能将无法提高。 但是办公室工作需要我尽快完成每项任务。大多数时候,项目的设计和体系结构不受我控制,我只能遵循与现有代码类似的样式。有时有一个设计不良的项目,但是还有另一个开发人员的设计技能比我强,他已经拥有重构该项目的整个计划,所以我只是遵循他的计划。我如何获得练习的机会?

5
最佳实践-如果在函数调用周围进行包装,而在函数处于保护状态时添加早退出
我知道这可能是非常特定于用例的,但是我发现自己经常想知道这一点。是否有一般首选的语法。 我不是在问函数中最好的方法是什么,我是在问应该早退还是应该不调用函数。 如果在函数调用周围包装 if (shouldThisRun) { runFunction(); } 具有if(保护)功能 runFunction() { if (!shouldThisRun) return; } 如果多次调用此函数,则后一种选项显然有可能减少代码重复,但是有时在此处添加它会带来错误,因为那样您可能会丢失该函数的单一职责。 这是一个例子 如果我有一个updateStatus()函数,该函数仅更新某些事物的状态。如果状态已更改,我只希望状态更新。我知道代码中状态可能发生变化的地方,也知道其他地方可能发生了变化。 我不确定它是否只是我自己,但是检查此内部函数感觉有点脏,因为我想使该函数尽可能保持纯净-如果我调用它,则希望状态得到更新。但是我无法说出将电话包裹在支票中的几个更好的地方,我知道它可能不会改变。

2
存储库模式与DAL对象创建
据我了解,IRepository应当包含CRUD。然后,我们继承了这个IRepository在我们的其它接口,如IProduct和落实IProduct具体类ProductRepository,用类似的方法GetAllProducts(),Top5Products()。 我们也可以对n层架构进行同样的操作。像,创建DAL Class Library并在它定义一个类Product以类似的方法GetAllProducts(),Top5Products()。 在这两个DAL.Product和Repo.ProductRepository我们初始化类DB Context的Entity Framework和查询我们的相关数据。 呼叫是在两个相似Repo.ProductRepository或DAL.Product从方法BLL 鉴于这些相似之处,我的问题是Repos有什么好处?我可以使用的多层架构与做同样的轻松得多(Controller,BLL Class Library,DAL Class Library)。

3
是否有理由不修改按值传递的参数的值?
是否有客观的,可支持的软件工程论据来支持或反对在函数主体中修改按值参数的值? 我团队经常发生的争吵(主要是很好玩)是是否应修改按值传递的参数。团队中的几个成员坚决决不应该将参数分配给它们,以便始终可以查询最初传递给该函数的值。我不同意并认为参数不过是通过调用方法的语法初始化的局部变量。如果按值参数的原始值很重要,则可以声明局部变量以显式存储该值。我不相信我们两个人都能很好地支持我们的立场。 这是无法解决的宗教冲突,还是在任一方向上都有好的客观的软件工程理由? 注意:原则问题仍然存在,无论特定语言的实现细节如何。例如,在JavaScript中,参数列表始终是动态的,参数可以视为从arguments对象初始化局部变量的语法糖。即使这样,也可以将参数声明的标识符视为“特殊”标识符,因为它们仍然捕获信息从调用者到被叫者的传递。

1
模式不是构建块–因此,我不应该在MVC / MVP模式上构建应用程序吗?
我读过这个页面设计模式,并编写代码时,你应该如何对待他们。据我了解,链接标题如下: 模式不是构件。 如果我理解正确,这意味着在有意义之前不要使用设计模式,对吗?不要一开始就说要使用策略模式,请等到编写一些代码为止,如果使用策略模式对您的设计有意义,那么就使用它。 创建GUI应用程序时,是否以相同方式对待MCV / MVP模式?从各自的链接,它说这是一种建筑模式。 假设如果我创建一个GUI应用程序并且不使用MCV / MVP模式,但是我的代码是干净,可读且可维护的,那么我是否仍未使用MCV / MVP模式仍然是代码异味/不良设计? ?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.