【问题标题】:When to use which pattern? [closed]什么时候使用哪种模式? [关闭]
【发布时间】:2010-09-21 12:09:30
【问题描述】:

作为一名初级开发人员,我对一些设计模式有些困惑。有时,我只是不知道在哪种情况下使用哪个。

例如,关于创建模式,我真的不知道什么时候使用:

  • 工厂
  • 原型
  • 建设者

实际上,我看到了一些差异;但我也看到您可以使用多种解决方案,例如:

  • 调用一个工厂,该工厂调用适当的构建器来克隆原型。
  • 调用克隆适当原型的工厂
  • 调用合适的主管的建设者
  • ...

我的意思是,这些创建的结果最终是一样的:你得到你的对象实例。

我只是想知道你会在不同的上下文中使用什么样的设计(我想这可能取决于性能需求、对象复杂性、耦合......)

另外,我看不出 facademediator 之间有什么大的区别,除了 mediator 调用不同的接口。

责任链也是如此,不太明白为什么我看到的所有实现都使用链表。这种模式不能用我们连续调用的简单的处理程序列表来实现吗?

这就是为什么我希望人们告诉我在哪个具体上下文中您会使用 GoF 模式,以及为什么您不会使用任何其他可能适合的模式给定的问题(但可能以不那么优雅的方式)。

谢谢

【问题讨论】:

标签: design-patterns language-agnostic oop


【解决方案1】:

和许多人一样,当我第一次接触设计模式时,我意识到其中很多只是我已经用来解决设计问题的机制的名称。问题首先出现,然后才是解决方案。我从来没有把设计模式当成拼图,需要放在某个地方。

您并不需要像考试一样回答模式名称的问题。这样做的方法是坐下来思考你需要你的代码做什么以及它在未来会如何改变。无论如何,这就是我们获得这些设计模式的方式。人们一直使用相同的技巧来解决某些问题,直到最终有人出现并为这些技巧命名。

您唯一的问题是缺乏经验,而这不能仅仅通过 SO 来解决。当你编写软件时,你总是会出错。您会发现,如果您以 这种 方式做事,它们会更好。顺便说一下这种方式有一个名字; “抽象工厂”、“适配器”、“观察者”等等。将来您会知道何时以及为何使用它。现在记住 KISS 原则。不要把不必复杂的事情复杂化。

您在知道如何使用设计模式之前就已经了解它们这一事实意味着您比大多数开发人员领先一步。不要出汗太多,只要记住下次遇到问题时,其中一个可能是可以接受的答案。渐渐地你会发现什么时候应该使用设计模式,什么时候不应该使用。

【讨论】:

  • +1 专门用于“你不需要像在考试一样回答模式名称的问题”
  • +1 为 KISS(额外字符)
  • +1 for “只是我已经使用过的机制的名称”。 模式不是你必须使用的东西。有人只是决定花时间写下所有解决方案,并一遍又一遍地“发明” - 并命名它们。通过阅读 GoF,您将在“发明”您自己的解决方案方面抢占先机——它可能已经被发明出来。它们可能已经很明显了,但现在它们有了名字。
  • 如果可以的话,我会再次为其余的答案 +1。
  • 这是一个比所选答案更好的答案。我会解释它,但它完美地说明了一切。
【解决方案2】:

这个答案我最想强调的是,我对另一个答案的这一点不同意:

第一次应用一个模式并理解它可能带来的好处是困难的(正如您所注意到的)

在应用它之前,您必须看到该模式将带来的明显好处。如果不是这种情况,请不要使用它,在代码中添加不能带来明显好处的模式很可能属于反模式场景

这就是为什么我希望人们告诉我在哪个具体上下文中您将使用 GoF 模式,以及为什么您不会使用任何其他可能适合给定问题的模式(但可能在不太优雅的方式)。

首先,不要将自己限制在您在那里阅读的内容中。模式的最佳方面是使您能够获得多种不同场景的设计选项。

当然,有些场景可以通过不止一种方式完成。在一个非常具体的场景中挣扎于两种模式之间的选择?再次检查它们,看看他们对场景和好处的看法。

如果您发现自己对大量的模式感到不知所措,请让大部分模式休息一下。不要一次将所有模式引入你的技能中。从中挑选一些相关的,并很好地了解何时应用它们(再次阅读它们,在 SO/博客文章中搜索/询问比较。

始终注意您应用的模式对更改的响应效果如何,以及围绕它们的代码的复杂性如何。问问自己这些特征与任何其他替代模式有何不同。

最后,了解您最好遵循不断发展的代码方法。尽最大努力保持代码干净,但不要执着于寻找永远不必改变的解决方案。即使手头有模式,您也会做出一些假设,这可能会影响您选择的模式。变化可能不符合那些假设,是事实还是生活。

阅读these 2 ebooks,可以极大地帮助您专注于如何设计/开发/改进代码。

【讨论】:

  • 老实说,我认为我们意见一致。如果没有考虑到好处,就无法应用模式。但是,在解决困扰我的问题之前,我当然无法理解“为什么”模式是有益的。到目前为止,它只是书中的图表。在需要 Singleton 之前,您可以编写大量代码。这并不能阻止所有读过 GOF 的人在每次想找借口使用全局变量时都试图挤入 Singleton。
  • @Steve 我完全同意您在此评论中所说的话。我最初阅读您答案的那部分的方式是:您使用它们的次数越多,您就会意识到它们的好处。这就是我们如何得到你刚才描述的情况,人们无缘无故地试图使用模式。我现在明白这不是你的意思。
【解决方案3】:

最初,我发现学习模式最简单的方法是遇到需要帮助的情况(太复杂而无法一目了然)然后实施。在遇到真正需要它的问题之前,很难理解为什么一种模式是有益的。

Joshua Kerievsky 的 'Refactoring to Patterns' 是一个很好的资源。

【讨论】:

  • +1 用于在我的回答评论中发布的澄清。我建议编辑这个答案的那一部分,以便更清楚。也许更符合评论:在遇到真正需要它的问题之前,很难理解为什么一种模式是有益的。
  • 好电话。感谢您的帮助。
【解决方案4】:

利用你创造的困惑:

  • Factory:创建几个派生类的实例

  • 原型:要复制或克隆的完全初始化的实例

  • Builder:将对象构造与其表示分离

我最近有一个案例,我需要构造一个实现接口的对象。我不知道,或者想知道,使用什么对象(或多个对象)来实现该接口。由于我个人想要隐藏对象,我不得不使用Factory

public class TransactionValidatorFactory
{
   public static IValidator CreateValidator(string RuleSet)
}


IValidator v = TransactionValidatorFactor.CreateValidator("Canada");

IValidator v = TransactionValidatorFactor.CreateValidator("UnitedStates");

IValidator v = TransactionValidatorFactor.CreateValidator("UnitedStates-Toyota");

IValidator v = TransactionValidatorFactor.CreateValidator("en-US");

我已经隐藏了工厂内使用的对象 - 只要我得到一个界面,我就可以开始了。

我什至不想查看实现接口的对象 - 它们是一组复杂的对象,使用它们的人无需进入。有时需要一个对象,有时需要多个对象。这是我想隐藏在工厂内部的一个细节。


但是看看同样的情况,你似乎专注于使用prototype。这意味着您必须构造对象、设置属性,然后根据需要clone 它们。当您知道要使用什么对象时,这对您来说很好。您还必须在对象上编写.Clone() 方法。

想查看对象,我的对象不支持Clone() 方法,我不想写一个。这让我回到了Factory 模式。

【讨论】:

  • 当你给工厂一个参数来引导工厂创建一个特定的“隐藏”对象时,你不能也将一个参数传递给一个构建器(这里称为导演),它会返回想要的对象(实现你的界面)?也许在这种情况下,建造者也是某种工厂......我想它可能会增加一些无用的复杂性,但它几乎会做同样的事情
  • 重做代码使用Builder 模式对我没有帮助,它使事情变得更加复杂。当构造各种对象是一个复杂的过程时,我会使用Builder - 足够复杂,以至于编写一个旨在为我构造它的整个类。我不需要那个 - 只是new CanadaTransactionValidator()。实际上,我确实有一些情况,其中返回的Validator 对象之一是使用四个或五个子对象实现的。但即便如此,构造还不够复杂,以至于我需要创建一个专门用于创建对象的类。
  • 在我的例子中,意识到 a 不能使用 Director/Builder 模式也很重要;它不适合。您将Builder 传递给DirectorDirector 调用 builder 上的方法,然后创建构建器需要的对象。这意味着对于我需要的每种结果对象,我都需要一个 Builder 类。选择我需要的正确对象(和对象组合)是运行时代码的工作(在工厂中),而不是为所有可能的请求预先编写构建器。
  • 在我的真实系统中,返回的接口可以由 25 种不同的对象组合支持。我不想创建 25 个构建器。 a) 太过分了;构造不是那么复杂,我必须抽象成一个专门的构建器,而且 b)我懒得这样做
【解决方案5】:

我个人的观点是,设计模式本身在现实世界中的用途通常非常有限 - 我经常看到模式作为万能解决方案出售“你应该使用 X 模式”,而实际上在现实世界中不像教科书那么统一——软件开发也不例外。

虽然理解和识别模式很有用,但不要太在意尝试将“设计模式”应用于现实世界的问题,而是在解决自己的问题时使用设计模式的知识作为灵感,例如虽然我经常来解决方案涉及的方面可能看起来类似于工厂模式,我还没有编写一个名称中包含“工厂”一词的类。

如果真的像到处使用设计模式一样简单,那么我们都会失业! :-)

【讨论】:

    【解决方案6】:

    Factory:创建对象而不将实例化逻辑暴露给客户端。

    Prototype:使用原型实例指定要创建的对象种类,并通过复制此原型创建新对象。

    在创建实例(使用 new 运算符)代价高昂时使用此模式。通常clone() 用于从现有对象创建对象。

    Builder: 将复杂对象的构造与其表示分开

    当您必须创建具有很少强制属性和许多可选属性的对象时,请使用此模式。提供构造函数来创建具有所有必需和可选属性的对象很复杂。 Builder 通过循序渐进的方法来促进这个构建过程。

    Builder 专注于逐步构建一个复杂的对象。抽象工厂强调一系列产品对象(简单或复杂)。 Builder 作为最后一步返回产品,但就抽象工厂而言,产品会立即返回。

    Facade 为复杂系统提供了一个简化的接口。它使用一个精心设计的 API 封装了一组 API。

    Mediator 模式定义了一个对象(中介者),它封装了一组对象如何交互。它支持多对多通信。

    相关帖子:

    Design Patterns: Factory vs Factory method vs Abstract Factory

    Keeping builder in separate class (fluent interface)

    What is Facade Design Pattern?

    Mediator Vs Observer Object-Oriented Design Patterns

    【讨论】:

      猜你喜欢
      • 2011-06-29
      • 2012-02-01
      • 2010-09-24
      • 2012-03-24
      • 2010-09-10
      相关资源
      最近更新 更多