图2中关键中Factory模式的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现:Factory中只是提供了对象创建的接口,其实现将放在Factory的子类ConcreteFactory中进行。这是图2和图1的区别所在。
Factory模式在实际开发中应用非常广泛,面向对象的系统经常面临着对象创建问题:要创建的类实在是太多了。而Factory提供的创建对象的接口封装(第一个功能),以及其将类的实例化推迟到子类(第二个功能)都部分地解决了实际问题
Factory模式也带来至少以下两个问题: 1)如果为每一个具体的ConcreteProduct类的实例化提供一个函数体,那么我们可能不得不在系统中添加了一个方法来处理这个新建的ConcreteProduct,这样Factory的接口永远就不肯能封闭(Close)。当然我们可以通过创建一个Factory的子类来通过多态实现这一点,但是这也是以新建一个类作为代价的。 2)在实现中我们可以通过参数化工厂方法,即给FactoryMethod()传递一个参数用以决定是创建具体哪一个具体的Product(实际上笔者在VisualCMCS中也正是这样做的)。当然也可以通过模板化避免1)中的子类创建子类,其方法就是将具体Product类作为模板参数,实现起来也很简单.
Factory模式仅仅局限于一类类(就是说Product是一类,有一个共同的基类),如果我们要为不同类的类提供一个对象创建的接口,那就要用AbstractFactory了。AbstractFactory模式就是用来解决这类问题的:要创建一组相关或者相互依赖的对象。
AbstractFactory模式关键就是将这一组对象的创建封装到一个用于创建对象的类(ConcreteFactory)中,维护这样一个创建类总比维护n多相关对象的创建过程要简单的多
AbstractFactory模式和Factory模式的区别是初学(使用)设计模式时候的一个容易引起困惑的地方。实际上,AbstractFactory模式是为创建一组(有多类)相关或依赖的对象提供创建接口,而Factory模式正如我在相应的文档中分析的是为一类对象提供创建接口或延迟对象的创建到子类中实现。并且可以看到,AbstractFactory模式通常都是使用Factory模式实现(ConcreteFactory1)。
Builder模式和AbstractFactory模式在功能上很相似,因为都是用来创建大的复杂的对象,它们的区别是:Builder模式强调的是一步步创建对象,并通过相同的创建过程可以获得不同的结果对象,一般来说Builder模式中对象不是直接返回的。而在AbstractFactory模式中对象是直接返回的,AbstractFactory模式强调的是为创建多个相互依赖的对象提供一个同一的接口。
如果类X的一个实例对象x调用了类Y的一个实例对象y的方法,那么就称类X依赖于类Y。为了打破这种依赖——“反转”,首先我们可以引入一个接口I(第三方类),接口I中声明了对象y将被对象x调用的所有方法;然后,我们对类Y稍加改造,使其实现接口I;最后,我们把在对象x中对y的调用改为对接口I中对应方法的调用。经过这番改造后,原先的X对Y的依赖关系不存在了,类X和Y现在都依赖于接口I。这种通过引入接口I来消除类X对Y的依赖的方法,被称作“控制反转”。
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。对于两个独立变化的维度,使用桥接模式再适合不过了。
Strategy模式和Template模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦。Strategy模式将逻辑(算法)封装到一个类(Context)里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现。Template是采用继承的方式实现算法的异构,其关键点就是将通用算法封装在抽象基类中,并将不同的算法细节放到子类中实现。
Strategy模式和State模式也有相似之处,但是State模式注重的对象在不同的状态下不同的操作。两者之间的区别就是State模式中具体实现类中有一个指向Context的引用,而Strategy模式则没有
在Observer模式的实现中,Subject维护一个list作为存储其所有观察者的容器。每当调用Notify操作就遍历list中的Observer对象,并广播通知改变状态(调用Observer的Update操作)。目标的状态state可以由Subject自己改变(示例),也可以由Observer的某个操作引起state的改变(可调用Subject的SetState操作)。Notify操作可以由Subject目标主动广播(示例),也可以由Observer观察者来调用(因为Observer维护一个指向Subject的指针)。
运行示例程序,可以看到当Subject处于状态“old”时候,依赖于它的两个观察者都显示“old”,当目标状态改变为“new”的时候,依赖于它的两个观察者也都改变为“new”。
设计模式可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种,创建型模式主要用于描述如何创建对象,结构型模式主要用于描述如何实现类或对象的组合,行为型模式主要用于描述类或对象怎样交互以及怎样分配职责,在GoF 23种设计模式中包含5种创建型设计模式、7种结构型设计模式和11种行为型设计模式。此外,根据某个模式主要是用于处理类之间的关系还是对象之间的关系,设计模式还可以分为类模式和对象模式。我们经常将两种分类方式结合使用,如单例模式是对象创建型模式,模板方法模式是类行为型模式。
- Factory Method(工厂方法)
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
适用性:
当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
- Abstract Factory(抽象工厂)
意图:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用性:
一个系统要独立于它的产品的创建、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
- Prototype(原型)
意图:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
- Bridge(桥接)
意图:
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
适用性:
你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。
类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge 模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
(C++)你想对客户完全隐藏抽象的实现部分。在C++中,类的表示在类接口中是可见的。
有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分。Rumbaugh 称这种类层次结构为“嵌套的普化”(nested generalizations )。
你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。一个简单的例子便是Coplien 的String 类[ Cop92 ],在这个类中多个对象可以共享同一个字符串表示(StringRep )。
1、代理模式:代理是原对象的代表,代理的客户无法直接访问目标对象,客户需要与目标对象打的任何交道都要和代理交涉。
代理模式中的原类和代理类继承同一父类;
原对象和代理对象接口相同,功能一致。
2、适配器模式:因为新旧接口不一致导致出现客户端无法满足的问题,旧的接口因为某些原因不能完全重构掉,将新旧接口之间增加一种转换,使之可以衔接。
只有适配器继承目标接口;
将原类接口转换成目标代码需求的接口;
会保存一个被适配的对象。
3、桥接模式:将可变点抽离出来,是适应多个维度变化、新需求不断增加的一种模式。虽然不管什么场景什么模式都可以抽象场景的一个子类,但是,这样会以乘法的速度增加,一味继承不是好的办法,毕竟子类和父类有非常紧密的联系,桥接模式正是组合/聚合复用原则的体现(尽量使用合成/聚合,尽量不要使用继承)。