设计模式纵横谈
设计模式原则
1、单一职责原则(SRP):
一个类应有仅有一个引起它变化的原因。 2、开放封闭原则(OCP):
类模块应该是可扩展的,但是不可修改(对扩展开放,对更改封闭)。内模块不可以修改,但可以新增功能。
3、Liskov替换原则(LSP):
子类必须能够替换它们的基类。如果调用的是父类的话,那么换成子类也完全可以运行。 4、依赖倒置原则(DIP):
高层模块(改变速度慢)不应该依赖于低层模块(改变速度快),二者都应该依赖于抽象。抽象不应该依赖于实现细节,实现细节应该依赖于抽象。主要是在构造对象时可以动态的创建各种具体对象,当然如果一些具体类比较稳定,就不必在弄一个抽象类做它的父类,这样有画蛇添足的感觉。 5、接口隔离原则(ISP):
不应该强迫客户程序依赖于它们不用的方法。定制服务的例子,每一个接口应该是一种角色,不多不少,不干不该干的事,该干的事都要干 。 6、合成/聚合复用原则
少用继承,多用合成关系来实现。
模式分类
1、从目的来看:
创建型(Creational)模式:负责对象创建。
单件模式、抽象工厂模式、建造者模式、工厂模式、原型模式。 结构型(Structural)模式:处理类与对象间的组合。
适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 行为型(Behavioral)模式:类与对象交互中的职责分配。
模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。 2、从范围来看:
类模式处理类与子类的静态关系。 对象模式处理对象间的动态关系。
Singleton单件(创建型模式)
一、动机(Motivation)
特殊类,在系统中只存在一个实例。如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
二、意图(Intent)
保证一个类仅有一个实例,并提供一个该实例的全局访问点。 三、单线程Singleton模式实现
Singleton模式中的实例构造器可以设置为protected以允许子类派生。 Singleton模式一般不要支持ICloneable接口(实例的克隆),因为这可能会导致多个对象实例,与Singleton模式的初衷违背。
Singleton模式一般不要支持序列化,因为这也可能导致多个对象实例。
Singleton模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收平台和对象的开销来讲,我们一般没有必要对其销毁进行特殊的管理。 不能应对多线程环境。
public class Singleton
{ private static Singleton instance; private Singleton() { }
public static Singleton Instance { get
{ if(instance == null)
instance = new Singleton(); return instance;} }}
私有的实例构造器是为了屏蔽默认产生的构造器,让类的使用者无法调用构造器。 四、多线程Singleton模式实现
public class Singleton
{ private static volatile Singleton instance; private static object lockHelper=new Object(); private Singleton() { }
public static Singleton Instance { get
{ if(instance==null) { lock (lockHelper) if(instance==null)
instance = new Singleton();} return instance;} }}
volatile修饰:编译器在编译代码的时候会对代码的顺序进行微调,用volatile修饰保证了严格意义的顺序。一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
Abstract Factory抽象工厂(创建型模式)
一、new的问题
常规的对象创建方法: Road road=new Road(); New的问题:
实现依赖,不能应对“具体实例化类型”的变化。 解决思路:
封装变化点——哪里变化,封装哪里。
面向接口编程——依赖接口、而非依赖实现。 最简单的解决方法: Class RoadFactory{
Public static Road CreateRoad(){
Return new Road();}}
客户程序:Road road = RoadFactory.CreateRoad(); 二、如何解决
使用面向对象的技术来“封装”变化点。 三、动机
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。 四、意图
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。 五、要点
如果没有应多“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的静态工厂完全可以。
“系列对象”指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的“道路”与“房屋”的依赖,“道路”与“地道”的依赖。 Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。 Abstract Factory模式经常和Factory Method模式共同组合来应对“对象创建”的需求变化。
Factory Method工厂方法模式(创建型模式)
一、从耦合关系谈起
耦合关系直接决定着软件面对变化时的行为
——模块与模块之间的紧耦合使得软件面对变化时,相关的模块都要随之更改 ——模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者更改,但其他模块保持不变。 二、动机
在软件系统中,经常面临着“某个对象”的创建工作:由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。
如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖该对象的对象”不随着需求的改变而改变? 三、意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 四、要点 Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。 Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,比较好地解决了这种紧耦合关系。 Factory Method模式解决“单个对象”的需求变化,Abstract Factory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。 汽车:
abstract class AbstractCar {
public void Startup(); public void Run();
public void Turn(Direction direction); public void Stop();
} 汽车工厂:
abstract class CarFactory {
public abstract AbstractCar CreateCar(); }
public class HongqiCarFactory : CarFactory {
public override AbstractCar CreateCar() {
return new HongqiCar(); } } 红旗汽车:
public class Enginee { }
public class HongqiCar:AbstractCar {
Enginee enginee1; Enginee enginee2; Enginee enginee3; Enginee enginee4;
public override void Startup() { } public override void Run() { }
public override void Turn(Direction direction) { } public override void Stop(); }
汽车测试:
class CarTestFramework {
public void BuildTestContext(CarFactory carFactory) {
AbstractCar c1 = carFactory.CreateCar(); AbstractCar c2 = carFactory.CreateCar(); }
public void DoTest(AbstractCar car) {
car.Run(); }
public TestData GetTestData(AbstractCar car) {
TestData t = new TestData(); return t; } }
客户程序:
static void Main(string[] args) {
CarTestFramework carTestFramework = new CarTestFramework(); carTestFramework.BuildTestContext(new HongqiCarFactory()); }