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