c++设计模式
“组件协作”
模板模式:
定义:定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟 (变化)到子类中。Template Method使得子类可以不改变 (复用)一个算法的结构即可重定义(override 重写)该算法的 某些特定步骤。
总结:
Template Method模式是一种非常基础性的设计模式,在面向对 象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性) 为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本 实现结构。
除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用 你”的反向控制结构是Template Method的典型应用。
在具体实现方面,被Template Method调用的虚方法可以具有实 现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将 它们设置为protected方法。
策略模式:
定义:定义一系列算法,把它们一个个封装起来,并且使它们可互 相替换(变化)。该模式使得算法可独立于使用它的客户程 序(稳定)而变化(扩展,子类化)。
总结:
Strategy及其子类为组件提供了一系列可重用的算法,从而可以使 得类型在运行时方便地根据需要在各个算法之间进行切换。
Strategy模式提供了用条件判断语句以外的另一种选择,消除条件 判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需 要Strategy模式。
如果Strategy对象没有实例变量,那么各个上下文可以共享同一个 Strategy对象,从而节省对象开销。
观察者模式:
定义:定义对象间的一种一对多(变化)的依赖关系,以便当一个 对象(Subject)的状态发生改变时,所有依赖于它的对象都 得到通知并自动更新。
总结:
使用面向对象的抽象,Observer模式使得我们可以独立地改变目 标与观察者,从而使二者之间的依赖关系达致松耦合。
目标发送通知时,无需指定观察者,通知(可以携带通知信息作 为参数)会自动传播。
观察者自己决定是否需要订阅通知,目标对象对此一无所知。
Observer模式是基于事件的UI框架中非常常用的设计模式,也是 MVC模式的一个重要组成部分。
桥模式:
定义:将抽象部分(业务功能)与实现部分(平台实现)分离,使它们 都可以独立地变化。
总结:
Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固 有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓 抽象和实现沿着各自纬度的变化,即“子类化”它们。
Bridge模式有时候类似于多继承方案,但是多继承方案往往违背 单一职责原则(即一个类只有一个变化的原因),复用性比较差。 Bridge模式是比多继承方案更好的解决方法。
Bridge模式的应用一般在“两个非常强的变化维度”,有时一个 类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。
“对象创建”
工厂模式:
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使得一个类的实例化延迟(目的:解耦, 手段:虚函数)到子类。
总结:
Factory Method模式用于隔离类对象的使用者和具体类型之间的 耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导 致软件的脆弱。
Factory Method模式通过面向对象的手法,将所要创建的具体对 象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好 地解决了这种紧耦合关系。 Factory Method模式解决“单个对象”的需求变化。缺点在于要 求创建方法/参数相同。
抽象工厂模式:
定义:提供一个接口,让该接口负责创建一系列“相关或者相互依 赖的对象”,无需指定它们具体的类。
总结:
如果没有应对“多系列对象构建”的需求变化,则没有必要使用 Abstract Factory模式,这时候使用简单的工厂完全可以。
“系列对象”指的是在某一特定系列下的对象之间有相互依赖、 或作用的关系。不同系列的对象之间不能相互依赖。
Abstract Factory模式主要在于应对“新系列”的需求变动。其缺 点在于难以应对“新对象”的需求变动。
“对象性能”
单例:
定义:保证一个类仅有一个实例,并提供一个该实例的全局访问点。
总结:
Singleton模式中的实例构造器可以设置成protected以允许子类派生。
Signleton模式一般不要构造拷贝函数和clone接口,因为这又可能导致多个对象实例,与Singleton模式的初衷违背。
如何实现多线程环境下安全的Singleton?注意对双检查锁的正确实现。
享元模式:
定义:运用共享技术有效支持大量细粒度的对象。
总结:
面向对象很好地解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
Flyweight采用对象共享的做法来降低对象中的个数,从而降低细粒度对象给系统带来的内存压力。在具体的实现方面,要注意对对象状态的处理。
对象数量太大从而导致对象内存开销加大-------什么样的数量才算大?这需要我们根据具体应用情况进行评估,而不能凭空猜测。
“接口隔离”
门面模式:
定义:为子系统中的一组接口提供一个一致(稳定)的界面,门面模式定义了一个高层接口,这个接口使得这个子系统更加容易使用(复用)。
总结:
从客户程序的角度来看,门面模式简化了整个组件系统的接口,对于组件内部与外部客户程序来说,达到了一种“解耦”的效果-------内部子系统的任何变化不会影响到门面模式接口的变化。
门面设计模式更注重从架构的层次去看整个系统,而不是单个类的层次,门面模式很多时候更是一种架构设计模式。
门面模式并非一个集中箱,可以任意地放进任何多个对象。门面模式中的组件的内部应该是“相互耦合关系比较大的一系列组件”,而不是一个简单的功能集合。
代理模式:
定义:为其他对象提供一种代理以控制(隔离,使用接口),对这个对象的访问。
总结:
“增加一层间接层”是软件系统中对许多复杂问题的一种常见解决办法。在面向对象系统中,直接使用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常见手段。
具体proxy设计模式的实现方法,实现粒度都相差很大,有些可能对单个对象做细粒度的控制,如copy-on-write技术,有些可能对组件模块提供抽象代理层,在架构层次对对象做proxy。
proxy不一定要求保持接口完整的一致性,只要能够实现间接控制,有时候损及一些透明性是可以接受的。
适配器模式:
定义:将一个类的接口转换为客户希望的另一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
Adapter模式主要用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用,类库迁移等方面非常有用。
GoF23定义了俩种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用了“多继承”的实现方式,一般不推荐使用。对象适配器采用“对象组合“的方式,更符合松耦合精神。
Adapter模式可以实现的非常灵活,不必拘泥于Gof23中定义的俩种结构。例如,完全可以将Adapter模式中的”现存对象“作为新的接口方法参数,来达到适配的目的。
中介者模式:
定义:用一个中介对象来封装(封装变化)一系列的对象交互,中介者使各对象不需要显式的相互引用(编译时依赖->运行时依赖),从而使得其耦合松散(管理变化),而且可以独立地改变他们之间的交互。
总结:
将多个对象间复杂的关联关系解耦,Mediator模式将多个对象间的控制逻辑进行集中管理,变“多个对象互相关联”为“多个对象和一个中介者关联”,简化了系统的维护,抵御了可能的变化。
随着控制逻辑的复杂化,Mediator具体对象的实现可能相当复杂。这时候可以对Mediator对象进行分解处理。
Facade模式是解耦系统间(单向)的对象关联关系;Mediator模式是解耦系统内各个对象之间(双向)的关联关系。
“状态变化”
状态模式
定义:允许一个对象在其内部状态时改变它的行为。从而使对象看起来似乎修改了其行为。
总结:
State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态之间的解耦。
为不同的状态引入不同的对象使得状态转化变得更加明确,而且可以保证不会出现状态不一致的情况,因为转化是原子性的------即要么彻底转换过来,要么不转换。
如果State对象没有实例变量,那么各个上下文可以共享一个State对象,从而节省对象开销。
备忘录(memento)模式:
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态了。
总结:
备忘录存储原发器(Originator)对象的内部状态,在需要时恢复原发器状态。
备忘录模式的核心是信息隐藏,即存储转发其需要向外界隐藏信息,保持其封装性。但是同时又需要将状态保持到外界。
由于现代语言运行时都具有相当的对象序列化支持,因此往往采用效率较高,又比较容易正确实现的序列化方案来实现备忘录模式。
“数据结构”
组合模式:
定义:将对象组合成树形结构以表示“部分-整体”的结构层次。组合模式将使得用户对单个对象和组合对象的使用具有一致性(稳定性)。

浙公网安备 33010602011771号