设计模式整理总结(一):创建型模式

  大多抽象于特定语言的东西都比较难,设计模式便是其中之一。大家都说设计模式是前人工程实践中的经验,所以多读历史多看看前辈走过的路可以少挖点、少踩点坑,而且对设计意图熟练掌握后,对于快速阅读代码融入项目也是很有帮助的。
  据说设计模式最好使用范例ACE的源代码,不过对于这个“学之者生,用之者死”(了解到的华为、腾讯例外)的著名网络库,目前还没有接触的打算。其实之前自己也总结了一份wiki,但是感觉这东西用自然语言的方式来描述反而难以讲清楚,所以这里打算用starUML工具把这些设计模式重新画一下,配上GOF的经典定义和网络上的一些典型例子,便于大家快速查阅和回忆。
  UML工具觉得starUML听轻巧好用的,其v1分支版本原来是开源的,但是后来作者抱怨缺少sponsor,所以新的v2已经闭源商业版了。其实starUML可以无限期的evaluate,而且网上所谓的破解就是简单粘贴几行代码,可见作者还是很良心大度的,目的也在于防君子不防小人了,经济自由的还是适当赞助这些慷慨的码农吧!
  在使用starUML的过程中,甚至不需要了解UML语言本身,图形化的操作就可以快速设计出模型。在使用starUML的时候,建议安装C++插件,可以帮助reverse分析已有代码的设计,可以将当前的设计自动生成C++代码。
UML
  UML中的难点,是依赖(Dependency)、继承(Generalization)、关联(Assosiciation)、聚合(Aggregation)、组合(Composition)这几种关系Relationships的理解和区分,其实粗分类来也就前三种,聚合和组合是关联关系特化一些条件的结果。
  (1) Dependency
  体现的是一种using的类与类之间的关系,而且这种关系是单向的。这种依赖关系体现在对一个被依赖类的结构或者行为改变,会影响到依赖于它的类。
  (2) Generalization
  体现的是一种is-a-kind-of或者is-a的关系,即常见的派生/继承关系。
  (3) Assosiciation
  表述的是除了上面两种方式之外类与类的联系,可以是一对多、多对一、一对一、多对多的关系,而且这种关系体现没有拥有的联系。如果在设计中不能确定区分出下面的Aggregation、Composition,可以模糊地使用Assosiciation表示。
  (4) Aggregation
  特例化的Assosiciation关系,体现的has-a的ownership关系,部分可以离开整体而单独存在。
  (5) Composition
  特例化的Aggregation关系,部分不能离开整体而单独存在,所以是一种Strong/Dead的依赖关系。

  设计模式共分为三类:创建型、结构型、设计型。一篇文章整理起来比较冗长,所以分成了三篇。
  创建型模式主要包括:抽象工厂(Abstract Factory)、生成器/建造者(Builder)、工厂方法(Factory Method)、原型(Prototype)、单件(Singleton)五种类型。

一、抽象工厂(AbstractFactory)模式

  定义:提供一个创建一系列相关或者相互依赖对象的接口,而无序指定他们具体的类。
AF
  抽象工厂可以算是工厂方法的更高级一层次的抽象。AbstractFactory类可以包括多个生成某种类型的工厂方法的接口,然后再由ConcreteFactory负责具体产品的创造实现。AbstractProduct为某一类的产品声明接口,然后ConcreteProduct实现这些接口后,就可以创建该类型的实际对象了。
  举例:AbstractFactory定义了用户界面工具包创建的接口,然后ConcreteFactory可以指明具体Motif、PM风格包的创建方法;而AbstractProduct指明了风格包需要操作窗口的Window、Scrollbar控件,那么经过组合之后就可以得到四种不同类型的ConcreteProduct产品了。

二、生成器/建造者(Builder)模式

  定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
Builder
  其通过将一个产品的内部表象和产品生成过程分割开来,从而一个建造过程可以生成具有不同内部表示的产品对象,用户只需要指定需要建造的类型就可以得到他们,而具体的建造过程和细节不需知道了。
  Builder为创建一个Product对象的各个部件指定抽象接口,ConcreteBuilder实现Builder定义的创建接口以构造和装配产品的各个部分,同时ConcreteBuilder需要提供一个检索产品的接口,Director构造一个使用Builder接口的对象。
  构造过程可以表示为:Client首先创建目的ConcreteBuilder对象,然后用其作为参数创建Director对象,通过调用Director的Construct()方法,在这个函数中实际调用ConcreteBuilder的具体构建方法创建Product的各个部分,其GetResult()查询接口可以将构造的对象返回给Client。
  构造者模式通常用于创建一些复杂的对象,这些对象的内部构建间的顺序通常是稳定的,但不同的对象内部的构造面临着复杂的变化。而且这里没有给Product做出一层的抽象,因为这种模式默认生成出的Product差异巨大,产生抽象基类没有太大意义。
  举例:比如文档交互器将文档转换成各种格式,那么Client先根据需要创建需要的ConcreteBuilder(比如ASCIICov,TeXCov,TextCov),然后用这个对象作为参数创建Director对象,调用Director对象的Construct()方法就可以返回创建结果了。
  注意:咋看一下和模板方法十分的相像,只是Builder多了一个Director的角色。从分类看来Builder属于创建型模式,主要目的是创建和实例化对象,而模板方法属于行为模式,主要是对多个相似行为进行上层抽象,如果把Director去掉,那么生成模式可以退化成模板方法。

三、工厂方法(Factory Method)模式

3.1 简单工厂

  定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。通常也叫做参数化工厂方法。
  简单工厂的特点是需要在工厂类中判断需要创建的类型,从而创造相应的产品,而当需要增加新的类型时,就需要修改简单工厂类本身。该模式的最大优点是工厂类中包含了必要的逻辑判断,根据客户端的选择参数动态实例化相关的类,对Client来说使用简单,免除了与具体产品的依赖。但是增加、减少、修改产品的操作都需要对简单工厂类代码进行变动,违反了开放-封闭原则。

3.2 工厂方法

  定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,使得一个类的实例化延迟到其子类。
FM
  像往常一样,Product和ConcreteProduct定义了具体产品的接口和其实现,Creator声明了工厂方法的接口FactoryMethod(),该方法返回一个Product类型的对象,ConcreteCreator实现Creator定义的FactoryMethod(),并返回一个ConcreteProduct实例。实际中Creator也可以提供一个默认的对象构造。
  工厂方法模式实现的时候,客户端决定实例化哪个具体的ConcreteCreator类型,把简单工厂的内部逻辑判断转移到了客户代码中了,所以工厂方法是简单工厂模式的进一步抽象和推广。工厂方法每增加一个类型,就需要增加一个对应的工厂类,所以工厂方法中类的数目会比较多。

四、原型(Prototype)模式

  定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,拷贝是原型模式的关键所在。
Proto
  Prototype声明一个克隆自身的Clone()接口,ConcretePrototype()负责实现克隆自身的操作。其主要限制是每一个Prototype的子类都必须实现Clone()操作,才能实现对象的完整克隆。此外在克隆的时候,需要注意浅复制和深复制的区别。
  Prototype模式原理实现比较简单,但是重点在于其使用场景和价值:原型模式从一个对象创建另外一个可定制的对象,而不需要知道任何创建的细节;原型模式通常会产生一个原型管理器,然后允许客户在运行时候动态的增加、删除、修改原型实例,更加的灵活;通过修改参数、修改结构等方式,可以扩充原型实例的数目,而不需要原先为产生这些类型而修改创建细节。

五、单件(Singleton)模式

  定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
Single
  Instance()操作允许客户访问它的唯一实例,在C++中通常是一个静态类方法和static局部变量。
  关于单例的讨论问题,已经在另外一篇文章说说设计模式中的单例中讨论过了,此处不再细究。

本文的starUML文件上传到了这里,欢迎使用!同时随着我的认识,本文件和本系列文档也会持续更正滴。

参考