关于生成设计模式的一些知识

设计模式的主题很受欢迎。 拍摄了很多视频,并撰写了文章。 将所有这些材料与“反模式”结合在一起。偶然的复杂性。 结果,示例繁琐,描述混乱,如何应用尚不清楚。 设计模式的主要任务-简化(代码和一般工作)无法实现。 毕竟,使用模板需要付出额外的努力。 与单元测试大致相同。


我将尝试就如何应用设计模式,在何处以及为什么进行解释。


六个生成器可以归因于:


  • 样机
  • 抽象工厂
  • 工厂方法
  • 建造者
  • 辛格尔顿
  • 延迟初始化。

与生成器有关的所有其他模式都是特殊的应用情况,没有必要再赘述了。


生成模式可将其回答的问题分为三组。 因此,三个问题:


  • 在哪
  • 怎么了
  • 什么时候

在哪


三种模式回答了这个问题:原型,抽象工厂和工厂方法。


关于条款的一点点

在OOP概念的框架内,理论上只有三个地方可以生成一个新实例。


  • 产品是实例化的类。
  • 客户端是将使用实例化实例的类。
  • 合作伙伴-客户可见度领域中的任何第三等。


实际上,这些模式决定了产生的地点。 此外,它们是分层连接的,并且具有不同的范围。 该连接如图所示,箭头确定呼叫方向。


生成模式的层次

在其实现中,“工厂方法”可以将实例的生成委派给现有的“工厂”或“原型”。 但是,“原型”不应依赖任何人,而是自己做任何事情。 现在更详细。


“原型”


该模板对应于位置“ Product”,实际上是该类的构造函数。 因此,总是生成特定(先前已知)类的实例。
在此模板的框架内,构造函数仅知道直接传递给它的参数(参数的数量趋向于类字段的数量)。 当然,可以完全访问所创建类的所有字段和属性。


正确实现的“原型”方法可让您摆脱公共的其他初始化方法。 反过来,该类的外部接口也变得更容易,也更不愿意将其用于其他目的。


该模板为我们提供了什么:


  • 连通性低-类仅了解自己,不依赖外部数据;
  • 可扩展性-可以重新定义构造函数或将其添加到后代;

缺点:


  • 对于复杂的类,您可能需要传递许多参数以进行初始化。 虽然有一个简单的解决方案。
  • 在客户端中直接使用会损害可读性,并实际上阻止了覆盖在客户端后代中生成的实例类型的可能性。

最受欢迎的模板。 每个人都在使用它,但很少有人知道它的用途。 在获得第一个工作模型之前,直到完全定义类及其关系之前,这是很好的方法。 之后,必须进行处理并增加抽象度。


“抽象工厂”


一些班级的伙伴。 它可以是专用的,也可以是“组合”的。 可能是静态的(无实例)。 “合并”的一个示例可以是配置类。 它也可能隐藏在立面的后面。


“工厂”通常查看应用程序(或单独的子系统)的所有全局设置。 立即生成可以委托给原型。 同时,Factory方法中输入参数的数量将少于类似的Prototype构造函数中的输入参数的数量。 工厂不会根据传入的参数决定由谁创建。


该模板非常方便且易于实现,但需要进行初步设计。 如果为所有内容创建工厂,这将使代码复杂化。 实际上,我们得到了Prototype的类似物,但转到了第三方类。


从优点:


  • 重新定义后代
  • 简化通话
  • 在工厂的基础上,很容易实现替换(状态模板)

但是也有缺点:



  • 它需要设计,特别是对于通用工厂(在许多项目中使用)。 换句话说,立即建立一个好的工厂并不容易。
  • 弄乱代码很容易,主要有两个方面:
    • 滑向原型,但在室外课堂上。 方法重载了参数;方法本身也很多。 结果,无论在工厂本身还是在客户端中,继承都是困难的。
    • 工厂采用通用方法。 此方法根据传递的参数返回任何实例。 结果与第一种情况相同。


很受欢迎 参加GoF课程的人员使用此模板。 通常,代码变得比“应用模板之前”更糟糕。


当工厂在第一次代码返工期间出现时,这是有意义的。 在此阶段,已创建实例的参数组合是已知的,编写通用化的Factory方法并不困难。 结果,将简化客户端中的呼叫。


在某些情况下,将工厂隐藏在立面后面很方便。 例如,该应用程序有十二个工厂和十二个库。 对于他们来说,您可以构建立面。 这将允许不将库链接到每个模块,并且很容易用另一个工厂替换一个工厂。


工厂方法


生成模式中的抽象顶部。 原产地客户。 将每种产品置于“工厂方法”中的类别都有很长的使用寿命。 如果没有狂热主义,则假定的发展轴必须必须基于此模板。


工厂方法没有超出其类的范围。 直接传输的参数的数量应最少(限制为零)。 在构建方法本身时,必须考虑到后代重叠的可能性。


一个常见的错误是使用一种方法进行复杂的初始化。 例如,当创建一个复杂的实例(Builder模板)时,将来对象的所有部分的创建都放在一种方法中。 结果,这种方法在后代中很难重叠。


从优点:


  • 匹配模板模板方法会很容易
  • 我们得到了简洁的代码,其中的逻辑清晰可见(不需要在大量的方法和参数中查看它)

基本上没有缺点。


该模板几乎从未使用过。 通常,只有在进行了深入初步准备的项目中才能看到它。 当工厂方法将生成委托给“工厂”或“原型”时,是理想选择。


小例子


我们有一个用于记录硬盘上文件的类。 这是“哪里”模式中的通用方法的外观:


原型:


constructor Create(aFilename: string; aLogLevel: TLogLevel); 

设计师应该知道的所有信息都以参数的形式传递给他。


工厂:


 function GetLogger(aLogLevel: TLogLevel): ILogger; 

根据应用程序设置,工厂知道要写入哪个文件。


工厂方法:


 function NewLogger: ILogger; 

在Client类中,知道要记录什么详细信息。


在此设计中,为了用存根替换日志记录类,足以在客户端的后代中重新定义NewLogger。 这在进行单元测试时很有用。


要登录到数据库,只需在Factory的后代中覆盖GetLogger方法即可。

Source: https://habr.com/ru/post/zh-CN467817/


All Articles