C#面向对象设计模式纵横谈
C#面向对象设计模式纵横谈
面向对象设计模式与原则
- 针对接口编程,而不是针对实现编程
- 优先使用对象组合,而不是类继承
- 封装变化点
- 使用重构得到模式---设计模式的应用不宜先入为主
设计原则
- 单一职责原则(SRP)
- 开放封闭原则(OCP)
- (里氏)Liskov替换原则(LSP)
- 依赖倒置原则(DIP)
- 接口隔离原则(ISP)
- 组合重用
- 迪米特(最小知识)原则
23种设计模式 (1-5,6-12,13-23)
1.Singleton单例模式
动机(Motivation)
在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性以及良好的效率
如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
这应该是类设计者的责任,而不是使用者的责任
意图(Intent)
保证一个类仅有一个实例,并提供一个实例的全局访问点。
结构(Struct)
2.Abstract Factory抽象工厂模式
动机(Motivation)
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列”具体对象创建工作的紧耦合?
意图(Intent)
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们 的具体类。
结构(Struct)
3.Builder生成器模式
动机(Motivation)
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合起来的算法却相对稳定。
如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
意图(Intent)
将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
结构(Struct)
4.Factory Method工场方法模式
动机(Motivation)
在软件系统中,经常面临着“某个对象”的创建工作;由于需求的变化,这个对象经常面临着剧烈的变化,但是他们拥有比较稳定的接口。
如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖该对象的对象”不随着需求改变而改变?
意图(Intent)
定义一个用于创建对象的接口,让子类决定实例化那一个类。Factory Method使得一个类的实例化延迟到子类。
结构(Struct)
5.Prototype原型模式
动机(Motivation)
在软件系统中,经常面临着“某些复杂对象”的创建工作;由于需求的变化,这个对象经常面临着剧烈的变化,但是他们拥有比较稳定的接口。
如何应对这种变化?如果向“客户程序(使用这些对象的程序)“隔离出”这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随需求改变而改变?
意图(Intent)
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
结构(Struct)
6.Adapter适配器模式
动机(Motivation)
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对这种“迁移的变化”?如何既能够利用现有对象的良好实现,同事又能满足新的应用环境所要求的接口?
意图(Intent)
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
结构(Struct)
7.Bridge桥接模式
动机(Motivation)
应对多维度的变化,Tank例子是“平台的变化”和“型号的变化”
如果应对这种“多维度的变化”,而不引入额外复杂度?
意图(Intent)
将抽象部分与实现部分分离,使它们你都可以独立地变化。
结构(Struct)
8.Composite组合模式
动机(Motivation)
客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维度、扩展性等弊端。
如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得 客户代码就像处理简单对象一样来处理复杂的对象容器?
意图(Intent)
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
结构(Struct)
9.Decorator装饰模式
动机(Motivation)
“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。
如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?
意图(Intent)
动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。
结构(Struct)
10.Facade外观模式
动机(Motivation)
组件的客户端和组件中各种复杂的子系统有了更多的耦合,随着外部客户程序和各个子系统的演化,这种过多的耦合面临很多变化的挑战。
如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统变化之间依赖相互解耦?
意图(Intent)
为子系统中的一组接口提供统一一致的界面,Facede模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
结构(Struct)
11.Flyweight享元模式
动机(Motivation)
采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时带价--只要指内存需求方面的代价。
如何避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?
意图(Intent)
运用共享技术有效地支持大量细粒度的对象。
结构(Struct)
12.Proxy代理模式
动机(Motivation)
在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者或者系统结构带来很多麻烦。
如何在不失去透明操作对象的同时来管理控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。
意图(Intent)
为其他对象提供一种代理以控制对这个对象的访问。
结构(Struct)
13.Template Method模板方法
动机(Motivation)
在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
意图(Intent)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法结构即可重定义该算法的某些特定步骤。
结构(Struct)
14.Command模式
动机(Motivation)
在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合--比如需要对行为进行“记录、撤销、重做”、事务等处理,这种无法抵御变化的紧耦合是不合适的。
在这种情况下,如何将“行为请求者”与“行为的“实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
意图(Intent)
将一个请求封装成为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
结构(Struct)
15.Interpreter解释器模式
动机(Motivation)
在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。
在这种情况下,将特定领域的问题表达为某种语法规则下的语句,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。
意图(Intent)
给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。
结构(Struct)
16.Mediator中介者模式
动机(Motivation)
在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。
在这种情况下,我们可以使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好的抵御变化?
意图(Intent)
用一个中介对象来封装一系列的对象交互。中介者使用各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
结构(Struct)
17.Iterator迭代器模式
动机(Motivation)
在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴漏其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为同一种算法在多种集合对象上进行操作提供可能。
使用面向对象技术将这种遍历机制抽象为“迭代器对象”应对“变化中的集合对象”提供一种优雅的方式?
意图(Intent)
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴漏该对象的内部表示。
结构(Struct)
18.Observer观察者模式
动机(Motivation)
在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”---一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合?
意图(Intent)
定义。
结构(Struct)
19.Chain of Responsibility职责链模式
动机(Motivation)
在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显式指定,将必不可少地带来请求发送者与接受者的紧耦合。
如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。
意图(Intent)
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,知道有一个对象处理它为止。
结构(Struct)
20.Mement备忘录模式
动机(Motivation)
在软件构建过程中,某些对象的状态在抓换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些共有接口来让其他对象得到对象的状态,便会暴漏对象的细节实现。
如何实现对象状态的良好保存于恢复?但同时又不会因此而破坏对象本身的封装性。
意图(Intent)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
结构(Struct)
21.State状态模式
动机(Motivation)
在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?
意图(Intent)
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。
结构(Struct)
22.Strategy策略模式
动机(Motivation)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
意图(Intent)
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立使用它的客户而变化。
结构(Struct)
23.Visitor访问者模式
动机(Motivation)
在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给予子类带来很繁重的变更负担,甚至破坏原有设计。
如何?
意图(Intent)
表示一个作用于某对象结构中的各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。
结构(Struct)
总结 (23)
创建型模式 (5)
- Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的都是new所带来的耦合关系。
- Factory Method,Abstract Factory,Builder都需要一个额外的工厂类来负责实例化“易变对象”,而Prototype则是通过原型(一个特殊的工程类)来克隆“易变对象”。
- 如果遇到“易变类”,起初的设计通常从Factory Method开始,当遇到更多的复杂变化时,在考虑重构为其他三种工厂模式(Abstract Factory,Builder,Prototype)
结构型模式 (7)
- Adapter模式注重转换接口,将不吻合的接口适配对接
- Bridge模式注重分离接口与其实现,支持多维度的变化
- Composite模式注重统一接口,将“一对多”的关系转化为“一对一”的关系
- Decorator模式注重稳定接口,再此前提下为对象扩展功能
- Facade模式注重简化接口,简化组件系统与外部客户程序的依赖关系
- Flyweight模式注重保留接口,在内部使用共享结束对对象存储进行优化
- Proxy 模式注重假借接口,增加间接层来实现灵活控制
行为型模式 (11)
- Template Method模式封装算法结构,支持算法子步骤变化
- Strategy模式注重封装算法,支持算法的变化
- State模式注重封装与状态相关的行为,支持状态的变化
- Mement模式注重封装对象状态的变化,支持状态保存/恢复
- Mediator模式注重封装对象间的交互,支持对象交互的变化
- Chain of Responsibility模式注重封装对象责任,支持责任的变化
- Command模式注重将请求封装为对象,支持请求的变化
- Iterator模式注重封装集合对象内部结构,支持集合的变化
- Interpreter模式注重封装特定领域变化,支持领域问题的频繁变化
- Observer模式注重封装对象通知,支持通信对象的变化
- Visitor模式注重封装对象操作变化,支持在运行时为类层次结构动态添加新的操作