C# 23种设计模式汇总 创建型模式 工厂方法(Factory Method) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节。工厂方法模式的核心是一个抽象工厂类,各种具体工厂类通过抽象工厂类将工厂方法继承下来。如此使得客户可以只关心抽象产品和抽象工厂,完全不用理会返回的是哪一种具体产品,也不用关系它是如何被具体工厂创建的。 抽象工厂模式(Abstract Factory) 抽象工厂模式的主要优点是隔离了具体类的生成,使得客户不需要知道什么被创建了。犹豫这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变这个软件的系统的行为。另外,应用抽象工厂模式符合GRASP纯虚构的模式,可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛应用。 建造者模式(Builder Pattern) 建造者模式将一个复杂对象的生成责任作了很好的分配。它把构造过程放在指挥者的方法中,把装配过程放到具体建造者类中。建造者模式的产品之间都有共通点,但有时候,产品之间的差异性很大,这就需要借助工厂方法模式或抽象工厂模式。另外,如果产品的内部变化复杂,Builder的每一个子类都需要对应到不同的产品去做构建的动作、方法,这就需要定义很多个具体建造类来实现这种变化。 单件模式(Single Pattern) Singleton单例模式为一个面向对象的应用程序提供了对象唯一的访问点,不管它实现何种功能,此种模式都为设计及开发团队提供了共享的概念。然而,Singleton对象类派生子类就有很大的困难,只有在父类没有被实例化时才可以实现。值得注意的是,有些对象不可以做成Singleton,比如.net的数据库链接对象(Connection),整个应用程序同享一个Connection对象会出现连接池溢出错误。另外,.net提供了自动废物回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是废物,自动消灭它并回收它的资源,下次利用时又会重新实例化,这种情况下应注意其状态的丢失。 原型模式(Protype Pattern) 原型模式得到了广泛的应用,特别是在创建对象成本较大的情况下(初始化需占用较长时间,占用太多CPU资源或网络资源。比如通过Webservice或DCOM创建对象,或者创建对象要装载大文件),系统如果需要重复利用,新的对象可以通过原型模式对已有对象的属性进行复制并稍作修改来取得。另外,如果系统要保存对象的状态而对象的状态变化很小,或者对象本身占内存不大的时候,也可以用原型模式配合备忘录模式来应用。相反地,如果对象的状态变化很大,或者对象占用内存很大,那么采用状态模式会比原型模式更好。原型模式的缺点是在实现深层复制时需要编写复杂的代码。 结构型模式 适配器模式(Adapter Pattern) 适配器模式可以将一个类的接口和另一个类的接口匹配起来,使用的前提是你不能或不想修改原来的适配器母接口(adaptee)。例如,你向第三方购买了一些类、控件,但是没有源程序,这时,使用适配器模式,你可以统一对象访问接口。但客户调用可能需要变动。 桥接模式(Bridge Pattern) 桥接模式可以从接口中分离实现功能,使得设计更具扩展性,这样,客户调用方法时根本不需要知道实现的细节。 桥接模式减少了子类,假设程序要在2个操作系统中处理6种图像格式,纯粹的继承就需要(2*6)12个子类,而应用桥接模式,只需要(2+6)8个子类。它使得代码更清洁,生成的执行程序文件更小。 桥接模式的缺陷是抽象类与实现类的双向连接使得运行速度减慢。 组合模式(Composite Pattern) 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新部件也更容易,因为它让客户忽略了层次的不同性,而它的结构又是动态的,提供了对象管理的灵活接口。组合模式对于树结构的控制有着神奇的功效,例如在人力资源系统的组织架构及ERP系统的BOM设计中,组合模式得到重点应用。 组合模式的缺陷是使得设计变得更加抽象。对象的商业规则如果很复杂,则实现组合模式具有很大挑战性,并且,不是所有的方法都与叶部件子类有关联。 装饰模式(Decorator Pattern) 装饰模式提供了比静态继承更好的柔韧性,它允许开发一系列的功能类用来代替增加对象的行为,这既不会污染原来对象的源码,还能使代码更容易编写,使类更具扩展性,因为变化都是由新的装饰类来完成。还可以建立连接的装饰对象关系链。 需要注意的是,装饰链不宜过长。装饰链太长会使系统花费较长时间用于初始化对象,同时信息在链中的传递也会浪费太多的时间。这个情况好比物品包装,包了一层又一层,大包套小包。另外,如果原来的对象接口发生变化,它所以的装饰类都要修改以匹配它的变化。派生子类会影响对象的内部,而一个Decorator只会影响对象的外表。 外观模式(Façade Pattern) 外观模式提供了一个简单且公用的接口去处理复杂的子系统,并且没有减少子系统的功能。它遮蔽了子系统的复杂性,避免了客户与子系统直接链接,它也减少了子系统与子系统间的连接,每个子系统都有它的Facade模式,每个子系统采用Facade模式去访问其他子系统。外观模式的劣势就是限制了客户的自由,减少了可变性。 享元模式(Flyweight Pattern) Flyweight模式需要你认真考虑如何能细化对象,以减少处理的对象数量,从而减少存留对象在内存或其他存储设备中的占用量。然而,此模式需要维护大量对象的外部状态,如果外部状态的数据量大,传递、查找、计算这些恶数据会变得非常复杂。当外部和内部的状态很难分清时,不宜采用flyweight模式。 代理模式(Proxy Pattern) 当对象在远程机器上,要通过网络来生成时,速度可能会慢,此时应用Remote Proxy模式,可以掩蔽对象由网络生成的过程,系统的速度会加快;对于大图片的加载,Virtual Proxy模式可以让加载在后台进行,前台用的Proxy对象使得整体运行速度得到优化;Protect Proxy可以验证对真实对象的引用权限。 代理模式的缺陷是请求的处理速度会变慢,并且实现Proxy模式需要额外的工作。 行为型模式 职责链模式(Chain of Responsibility) 责任链模式可以减少对象的连接,为对象责任分配增加了很大的灵活性。该模式允许把一组类作为一个类来使用,并且在类的组合中,一个类的事件可以发送到另一个类并由其处理。 责任链模式通常应用与图形用户界面中,窗体的部件可能会包含其他几个小部件,就如同Windows窗体应用程序中,控件中又可以放置其他控件,控件边界会决定是否处理事件,或者将事件传递给父控件来处理。 另外,责任链还会以树状出现,这样,一个事件可以传给多个类,或者,多个类的信息可以提交到一个类。树状责任链能够提供更灵活的技巧,但缺点是信息在树中容易迷失。 命令模式(Command Pattern) 命令模式分离了接受请求的对象与实现处理请求工作的对象,这样,已经存在的类可以保持不变,使得增加新类的工作更简单。例如,很多软件的宏命令就提高了系统的自动化程度。 命令模式还可以分离用户界面和业务对象,降低系统的耦合度。 但是,命令模式最主要的缺陷就是,类的数量增加了,系统变得更复杂,程序的调试工作也相应变得困难。 解释器模式(Interpreter Pattern) 解释器模式的作用很强大,它使得改变和扩展文法变得容易,实现文法也变得简单明了,很多编译器,包括文本编辑器、网页浏览器及VRML都应用解释器模式。 解释器模式的缺陷就是,因为文句会分析成树结构,解释器需要递归访问它,所以效率会受影响。这种情况开发人员会有所体会,编译整个工程源码耗费时间都比较长。 模版方法模式(Template Method) 模版方法模式在一个类中形式化地定义算法,而由它的子类实现细节的处理。模版方法模式的优势是,在子类定义处理算法时不会改变算法的结构。 模版方法的特点在于,每个不同的实现都需要定义一个子类,这也复合高内聚的责任分配模式,不能说成是它的缺点。 迭代器模式(Iterator Pattern) 迭代器模式支持在聚集中移动游标,使得访问聚合中的元素变得简单,简化了聚集的接口,封装了聚合的对象。 迭代器模式还可以应用于对树结构的访问,程序不需要从头逐行代码查找相应位置,可控制到从子集开始查找,对于加快程序的运行速度有很重要的作用。 迭代器模式的缺点是聚合密切相关,增加了耦合。但将这种耦合定义在抽象基类,可解决这个问题。 观察者模式(Oberver Pattern) 观察者模式抽象了被观察对象与观察者对象的连接,提供了广播式的对象间通信,并且容易增加新的观察者对象。观察者模式的缺陷是对象间的关系难以理解,在某种情况下会表现低效能。 中介者模式(Mediator Pattern) 中介者模式分离了两个同事类,简化了对象协议,中央控制对象交互,从而使个体对象变得更容易且更简单,因为它不需要传递数据给其他个体对象,仅仅传给中介者就可以了。个体对象不需要具有处理内部交流的逻辑,所以更加突出它的面向对象特性。 备忘录模式(Memento Pattern) Memento模式保存了封装的边界,一个Memento对象是另一种原发器对象的表示,不会被其他代码改动。这种模式简化了原发器对象,Memento只保存原发器的状态。采用堆栈备忘对象,可以实现多次取消操作。 状态模式(State Pattern) 状态模式在对象内保存特定的状态并且就不同的状态履行不同的行为,它使状态的变化显得清晰明了,也很容易创建对象的新状态。 状态模式在工作流或游戏等各种系统中大量使用,例如在政府OA系统中,一个批文的状态有多种:未办、正在处理、正在批示、正在审核和已经完成等各种状态。在网络游戏中,一个游戏活动存在开始、开玩、正在玩、输赢等各种状态。使用状态模式就可以实现游戏状态的总控,而游戏状态决定了游戏的各个方面。 策略模式(Strategy Pattern) 策略模式提供了替代派生的子类,并定义类的每个行为,剔除了代码中条件的判断语句,使得扩展和结合新的行为变得更容易,根本不需要变动应用程序。策略模式可以避免使用多重条件转移语句,系统变得更新灵活。应用策略模式会产生很多子类,这符合高内聚的责任分配模式。 访问者模式(Visitor Pattern) Visitor(访问者)模式使得增加新的操作变得容易,它可以收集有关联的方法,而分离没有关联的方法,特别适用于分离因为不同原因而变化的事物,如“在男人中分离出男孩”。但Visitor模式常常要打破对象的封装性,visitor与element需要达成某些共识。