关于语言不可知:何时使用哪种模式?

When to use which pattern?

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

例如,在创造模式方面,我不知道何时使用:

  • 工厂
  • 原型
  • 建设者

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

  • 调用一个工厂,该工厂调用复制原型的适当生成器。
  • 调用克隆适当原型的工厂
  • 与合适的主管联系建筑商

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

我只是想知道您将在不同的上下文中使用哪种设计(我想这可能取决于性能需求、对象复杂性、耦合…)

另外,除了中介调用不同的接口之外,我并没有看到外观和中介之间有很大的区别。

同样,对于责任链,也不真正理解为什么我看到的所有实现都使用链表。这个模式不能用我们连续调用的处理程序的简单列表来实现吗?

这就是为什么我想让人们告诉我,在什么具体的环境中,你会使用一个GOF模式,以及为什么你不会使用任何其他模式,可能适合给定的问题(但可能在一个不太优雅的方式)。

谢谢


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

你不需要像考试一样用模式的名字回答问题。做这件事的方法是坐下来思考你需要你的代码去做什么,以及它将来会如何改变。这就是我们如何得到这些设计模式的原因。人们一直使用相同的技巧来解决某些问题,直到最后有人出现并给这些技巧起了名字。

你唯一的问题是缺乏经验,而这不能仅仅靠经验来解决。当你写软件的时候,你总是会出错。你会发现,如果你这样做,他们会更好。顺便说一下,这种方式有一个名称:"抽象工厂"、"适配器"、"观察者",随便什么。将来你会知道何时以及为什么要使用它。现在记住接吻原则。不要把不必复杂的事情复杂化。

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


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

It's difficult (as you've noticed) to apply a pattern for the first time and understand what the benefits might be

在应用该模式之前,您必须看到它所带来的明显好处。如果不是这样的话,不要使用它,在代码中添加没有明显好处的模式很有可能是反模式的。

That's why i'd like people to tell me in which CONCRETE context you would use a GoF pattern, and also why you wouldn't use any of the other patterns that could have fit to the given problem (but probably in a less elegant way).

首先,不要局限于你在那里读到的内容。模式的最佳方面是使您能够获得几个不同场景的设计选项。

当然,有些场景可以用多种方式完成。在一个非常具体的场景中,在两种模式之间进行艰难的选择?再次检查他们,看看他们对场景和好处的看法。

如果你发现自己被大量的模式所淹没,那就让它们大部分休息一下。不要一次把所有的模式都引入到你的技能中。从中挑选一些相关的,并很好地了解何时应用它们(再次阅读它们,在SO/博客文章中搜索/要求比较)。

始终注意应用的模式对更改的响应有多好,以及它们周围代码的复杂性有多复杂。问问你自己,这些特征与其他任何可选模式有什么不同。

最后,请理解您最好遵循一种不断发展的代码方法。尽你最大的努力保持代码的整洁,但是不要总想着找到一个永远不需要改变的解决方案。即使有现成的模式,您也将采取一些假设,这可能会影响您选择的模式。变化可能与那些假设不符,是事实还是生活。

阅读这两本电子书,可以帮助您集中精力设计/开发/改进代码。


最初,我发现学习模式最简单的方法是遇到需要帮助的情况(太复杂,一眼都看不懂),然后实现它。很难理解为什么一个模式在你遇到真正需要它的问题之前是有益的。

一个很好的资源就是JoshuaKerievsky的"重构模式"。


使用你的创造困惑:

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

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

  • 生成器:将对象构造与其表示分离

最近我遇到了一个案例,我需要构造一个实现接口的对象。我不知道,也不想知道,是什么对象(或对象)用于实现该接口。因为我个人想把这些东西藏起来,所以我不得不用一个Factory

1
2
3
4
5
6
7
8
9
10
11
12
13
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模式。


工厂:创建对象而不向客户机公开实例化逻辑。

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

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

生成器:将复杂对象的构造与其表示分离

当必须创建具有少量强制属性和许多可选属性的对象时,请使用此模式。提供构造函数来创建具有所有强制和可选属性的对象是复杂的。Builder通过遵循逐步的方法简化了这一施工过程。

构建器的重点是逐步构造复杂的对象。抽象工厂强调一系列产品对象(简单或复杂)。Builder将产品作为最后一步返回,但就抽象工厂而言,产品将立即返回。

Facade为复杂系统提供了一个简化的接口。它用一个设计良好的API包装了一组API。

中介模式定义了一个对象(中介),它封装了一组对象如何交互。它使许多对许多的通信成为可能。

相关职位:

设计模式:工厂vs工厂方法vs抽象工厂

将生成器保持在单独的类中(Fluent接口)

什么是立面设计图案?

中介与观测者面向对象设计模式


我个人的观点是,设计模式本身在现实世界中的使用通常非常有限——我经常将销售的模式视为"你应该使用X模式"的一种适合所有人的解决方案,而实际上现实世界并不像教科书那样统一——软件开发也不例外。

虽然理解和识别模式是有用的,但不要过分担心试图将"设计模式"应用于现实世界的问题,而是在解决您自己的问题时,使用设计模式的知识作为灵感,例如,尽管我经常提出与工厂模式相似的方面的解决方案,但是还没有写一个名为"工厂"的类。

如果它真的像在所有地方使用设计模式一样简单,那么我们都将失业!-)