C#设计模式之总结篇
一、引言 ?????? 示例代码: 1 /// <summary> 2 /// 单例模式的实现 3 </summary> 4 public sealed class Singleton 5 { 6 // 定义一个静态变量来保存类的实例 7 private static volatile Singleton uniqueInstance; 8 9 定义一个标识确保线程同步 10 readonly object locker = new object(); 11 12 定义私有构造函数,使外界不能创建该类实例 13 private Singleton() 14 { 15 } 16 17 18 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 19 20 <returns></returns> 21 static Singleton GetInstance() 22 23 当第一个线程运行到这里时,此时会对locker对象 "加锁", 24 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁 25 lock语句运行完之后(即线程运行完之后)会对该对象"解锁" 26 双重锁定只需要一句判断就可以了 27 if (uniqueInstance == null) 28 { 29 lock (locker) 30 { 31 如果类的实例不存在则创建,否则直接返回 32 33 { 34 uniqueInstance = new Singleton(); 35 } 36 } 37 } 38 return uniqueInstance; 39 40 }
?????? 代码实例: 1 2 下面以不同系列房屋的建造为例子演示抽象工厂模式 3 因为每个人的喜好不一样,我喜欢欧式的,我弟弟就喜欢现代的 4 客户端调用 5 6 Client 7 8 void Main(string[] args) 9 10 哥哥的欧式风格的房子 11 AbstractFactory europeanFactory= EuropeanFactory(); 12 europeanFactory.CreateRoof().Create(); 13 europeanFactory.CreateFloor().Create(); 14 europeanFactory.CreateWindow().Create(); 15 europeanFactory.CreateDoor().Create(); 16 17 18 弟弟的现代风格的房子 19 AbstractFactory modernizationFactory = ModernizationFactory(); 20 modernizationFactory.CreateRoof().Create(); 21 modernizationFactory.CreateFloor().Create(); 22 modernizationFactory.CreateWindow().Create(); 23 modernizationFactory.CreateDoor().Create(); 24 Console.Read(); 25 } 26 } 27 28 29 抽象工厂类,提供创建不同类型房子的接口 30 31 abstract AbstractFactory 32 { 33 抽象工厂提供创建一系列产品的接口,这里作为例子,只给出了房顶、地板、窗户和房门创建接口 34 abstract Roof CreateRoof(); 35 Floor CreateFloor(); 36 Window CreateWindow(); 37 Door CreateDoor(); 38 } 39 40 41 欧式风格房子的工厂,负责创建欧式风格的房子 42 43 EuropeanFactory : AbstractFactory 44 45 制作欧式房顶 46 override Roof CreateRoof() 47 { 48 return EuropeanRoof(); 49 50 51 制作欧式地板 52 Floor CreateFloor() 53 54 EuropeanFloor(); 55 } 56 57 制作欧式窗户 58 Window CreateWindow() 59 60 EuropeanWindow(); 61 62 63 制作欧式房门 64 Door CreateDoor() 65 66 EuropeanDoor(); 67 68 69 70 71 现在风格房子的工厂,负责创建现代风格的房子 72 73 ModernizationFactory : AbstractFactory 74 75 制作现代房顶 76 77 78 ModernizationRoof(); 79 80 81 制作现代地板 82 83 { 84 ModernizationFloor(); 85 } 86 87 制作现代窗户 88 89 { 90 ModernizationWindow(); 91 } 92 93 制作现代房门 94 95 96 ModernizationDoor(); 97 98 } 99 100 101 房顶抽象类,子类的房顶必须继承该类 102 103 Roof 104 105 106 创建房顶 107 108 void Create(); 109 } 110 111 112 地板抽象类,子类的地板必须继承该类 113 114 Floor 115 { 116 117 创建地板 118 119 120 121 122 123 窗户抽象类,子类的窗户必须继承该类 124 125 Window 126 127 128 创建窗户 129 130 131 132 133 134 房门抽象类,子类的房门必须继承该类 135 136 Door 137 138 139 创建房门 140 141 142 143 144 145 欧式地板类 146 147 EuropeanFloor : Floor 148 149 override Create() 150 151 Console.WriteLine("创建欧式的地板"); 152 153 154 155 156 157 欧式的房顶 158 159 EuropeanRoof : Roof 160 161 162 163 Console.WriteLine(创建欧式的房顶164 165 166 167 168 169 欧式的窗户 170 171 EuropeanWindow : Window 172 173 174 175 Console.WriteLine(创建欧式的窗户176 177 178 179 180 181 欧式的房门 182 183 EuropeanDoor : Door 184 185 186 187 Console.WriteLine(创建欧式的房门188 189 190 191 192 现代的房顶 193 194 ModernizationRoof : Roof 195 196 197 198 Console.WriteLine(创建现代的房顶199 200 201 202 203 现代的地板 204 205 ModernizationFloor : Floor 206 207 208 209 Console.WriteLine(创建现代的地板210 211 212 213 214 现代的窗户 215 216 ModernizationWindow : Window 217 218 219 220 Console.WriteLine(创建现代的窗户221 222 223 224 225 现代的房门 226 227 ModernizationDoor : Door 228 229 230 231 Console.WriteLine(创建现代的房门232 233 }
??? 3.5、原型模式(Prototype Pattern):通过制定实例类型来复制对象 ?????? 动机(Motivate):在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变? ?????? 意图(Intent):使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。 ?????? 具体结构图如下所示: ?????????? 四、结构型模式 ??? 结构型模式主要研究的是类和对象的组合的问题。它包括两种类型,一是类结构型模式:指的是采用继承机制来组合实现功能;二是对象结构型模式:指的是通过组合对象的方式来实现新的功能。该系列模式包括:适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式和代理模式。 ??? 4.1、适配器模式(Adapter Pattern):该模式主要关注的是接口转换的问题,将匹配的接口通过适配对接工作。 ?????? 动机(Motivate):在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口? ?????? 意图(Intent):将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 ???????????????????? ? ? ? ? ? ?? 适配器模式意在转换接口,它能够使原本不能再一起工作的两个类一起工作,所以经常用来在类库的复用、代码迁移等方面。 适配器模式包括类适配器模式和对象适配器模式, ?????? 具体结构图如下所示: ?????? 类适配器模式: ??????????? ?????? 对象适配器模式: ???????????? ??? 4.2、桥接模式(Bridge Pattern):该模式注重分离接口与其实现,接口是针对客户的,接口的内在实现是通过“实现层次”来完成的,支持多维度变化。 ?????? 动机(Motivate):在很多游戏场景中,会有这样的情况:【装备】本身会有的自己固有的逻辑,比如枪支,会有型号的问题,同时现在很多的游戏又在不同的介质平台上运行和使用,这样就使得游戏的【装备】具有了两个变化的维度——一个变化的维度为“平台的变化”,另一个变化的维度为“型号的变化”。如果我们要写代码实现这款游戏,难道我们针对每种平台都实现一套独立的【装备】吗?复用在哪里?如何应对这种“多维度的变化”?如何利用面向对象技术来使得【装备】可以轻松地沿着“平台”和“型号”两个方向变化,而不引入额外的复杂度? ?????? 意图(Intent):将抽象部分与实现部分分离,使它们都可以独立地变化。 ?????????????????????? 比如:就拿游戏装备来说,“手枪”,抽象部分是指手枪的型号,这个型号可以是G50,G55,针对不同平台,这些型号有不同的实现,针对这些不同平台的不同型号的实现,重新抽象,抽象的结构就是“实现的层次”,其实,到此,就形成了两个抽象层次,第一个层次,是枪支的型号的层次,另一个层次就是针对其实现的一个层次,这样就做到了抽象和实现的分离。 ?????? 具体结构图如下所示: ?????????? ?????? 示例代码: 1 namespace 桥接模式的实现 2 { 4 该抽象类就是抽象接口的定义,该类型就相当于是Abstraction类型 5 6 Database 7 8 通过组合方式引用平台接口,此处就是桥梁,该类型相当于Implementor类型 protected PlatformImplementor _implementor; 10 11 通过构造器注入,初始化平台实现 Database(PlatformImplementor implementor) 13 14 this._implementor = implementor; 16 17 创建数据库--该操作相当于Abstraction类型的Operation方法 18 19 20 21 22 该抽象类就是实现接口的定义,该类型就相当于是Implementor类型 23 24 PlatformImplementor 25 26 该方法就相当于Implementor类型的OperationImpl方法 27 Process(); 29 30 31 SqlServer2000版本的数据库,相当于RefinedAbstraction类型 32 33 SqlServer2000 : Database 34 35 构造函数初始化 36 public SqlServer2000(PlatformImplementor implementor) : base(implementor) { } 37 38 40 this._implementor.Process(); 41 42 43 44 45 SqlServer2005版本的数据库,相当于RefinedAbstraction类型 46 47 SqlServer2005 : Database 48 49 50 public SqlServer2005(PlatformImplementor implementor) : 51 52 53 54 55 56 57 58 59 SqlServer2000版本的数据库针对Unix操作系统具体的实现,相当于ConcreteImplementorA类型 60 61 SqlServer2000UnixImplementor : PlatformImplementor 62 63 Process() 64 65 Console.WriteLine(SqlServer2000针对Unix的具体实现66 67 68 69 70 SqlServer2005版本的数据库针对Unix操作系统的具体实现,相当于ConcreteImplementorB类型 71 72 SqlServer2005UnixImplementor : PlatformImplementor 73 74 75 76 Console.WriteLine(SqlServer2005针对Unix的具体实现77 78 79 80 Program 81 82 Main() 83 84 PlatformImplementor SqlServer2000UnixImp = SqlServer2000UnixImplementor(); 85 还可以针对不同平台进行扩展,也就是子类化,这个是独立变化的 86 87 Database SqlServer2000Unix = SqlServer2000(SqlServer2000UnixImp); 88 数据库版本也可以进行扩展和升级,也进行独立的变化。 89 90 以上就是两个维度的变化。 91 92 就可以针对Unix执行操作了 93 SqlServer2000Unix.Create(); 94 95 96 }
?????? 示例代码: ???????? 装饰模式的实现 该抽象类就是房子抽象接口的定义,该类型就相当于是Component类型,是饺子馅,需要装饰的,需要包装的 House 房子的装修方法--该操作相当于Component类型的Operation方法 Renovation(); 10 11 12 13 该抽象类就是装饰接口的定义,该类型就相当于是Decorator类型,如果需要具体的功能,可以子类化该类型 14 15 class DecorationStrategy:House 关键点之二,体现关系为Is-a,有这这个关系,装饰的类也可以继续装饰了 16 17 通过组合方式引用Decorator类型,该类型实施具体功能的增加 这是关键点之一,包含关系,体现为Has-a 19 House _house; 22 DecorationStrategy(House house) 23 24 this._house=house; 26 27 该方法就相当于Decorator类型的Operation方法 28 Renovation() 29 30 if(this._house!=31 32 ._house.Renovation(); 36 37 38 PatrickLiu的房子,我要按我的要求做房子,相当于ConcreteComponent类型,这就是我们具体的饺子馅,我个人比较喜欢韭菜馅 39 40 PatrickLiuHouse:House 42 43 44 Console.WriteLine(装修PatrickLiu的房子45 46 47 48 49 50 具有安全功能的设备,可以提供监视和报警功能,相当于ConcreteDecoratorA类型 51 52 HouseSecurityDecorator:DecorationStrategy 54 public HouseSecurityDecorator(House house):(house){} 55 56 57 58 .Renovation(); 59 Console.WriteLine(增加安全系统60 61 62 63 64 具有保温接口的材料,提供保温功能,相当于ConcreteDecoratorB类型 65 66 KeepWarmDecorator:DecorationStrategy 68 public KeepWarmDecorator(House house):69 70 71 72 73 Console.WriteLine(增加保温的功能74 76 77 79 80 81 这就是我们的饺子馅,需要装饰的房子 82 House myselfHouse= PatrickLiuHouse(); 83 84 DecorationStrategy securityHouse= HouseSecurityDecorator(myselfHouse); 85 securityHouse.Renovation(); 86 房子就有了安全系统了 87 88 如果我既要安全系统又要保暖呢,继续装饰就行 89 DecorationStrategy securityAndWarmHouse= HouseSecurityDecorator(securityHouse); 90 securityAndWarmHouse.Renovation(); 91 92 93 } 命令模式的实现 俗话说:“好吃不如饺子,舒服不如倒着”。今天奶奶发话要吃他大孙子和孙媳妇包的饺子。今天还拿吃饺子这件事来说说命令模式的实现吧。 9 10 奶奶想吃猪肉大葱馅的饺子 11 PatrickLiuAndWife liuAndLai = new PatrickLiuAndWife();命令接受者 12 Command command = new MakeDumplingsCommand(liuAndLai);命令 13 PaPaInvoker papa = new PaPaInvoker(command); 命令请求者 14 15 奶奶发布命令 papa.ExecuteCommand(); 17 18 Console.Read(); 20 21 22 23 这个类型就是请求者角色--也就是我爸爸的角色,告诉奶奶要吃饺子 PaPaInvoker 我爸爸从奶奶那里接受到的命令 Command _command; 28 29 爸爸开始接受具体的命令 30 public PaPaInvoker(Command command) 32 this._command = command; 34 爸爸给我们下达命令 ExecuteCommand() 38 _command.MakeDumplings(); 40 41 42 该类型就是抽象命令角色--Commmand,定义了命令的抽象接口,任务是包饺子 43 Command 44 45 真正任务的接受者 46 PatrickLiuAndWife _worker; 47 48 Command(PatrickLiuAndWife worker) 49 50 _worker = worker; 51 52 53 该方法就是抽象命令对象Command的Execute方法 MakeDumplings(); 56 57 该类型是具体命令角色--ConcreteCommand,这个命令完成制作“猪肉大葱馅”的饺子 58 MakeDumplingsCommand : Command 59 60 public MakeDumplingsCommand(PatrickLiuAndWife worker) : (worker) { } 61 62 执行命令--包饺子 MakeDumplings() 65 执行命令---包饺子 66 _worker.Execute(今天包的是农家猪肉和农家大葱馅的饺子68 70 该类型是具体命令接受角色Receiver,具体包饺子的行为是我们夫妻俩来完成的 71 PatrickLiuAndWife 72 73 这个方法相当于Receiver类型的Action方法 void Execute( job) 76 Console.WriteLine(job); 79 }
??? 4.7、代理模式(Proxy Pattern):该模式注重假借代理接口,控制对真实对象的访问,通过增加间接层来实现灵活控制,比如可以在访问正真对象之前进行权限验证,生活中的明星的代理就是很好的例子,要想接触明星,先要和他的经纪人打交道。 ?????? 动机(Motivate):在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者、或者系统结构带来很多麻烦。如何在不失去透明操作对象的同时来管理/控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。 ?????? 意图(Intent):为其他对象提供一种代理以控制对这个对象的访问。 ?????? 具体结构图如下所示: ????????????? 五、行为型模式 ??? 行为型模式主要讨论的是在不同对象之间划分责任和算法的抽象化的问题。行为型模式又分为类的行为模式和对象的行为模式两种。 ??? 类的行为模式——使用继承关系在几个类之间分配行为。 ??? 对象的行为模式——使用对象聚合的方式来分配行为。 ??? 行为型模式包括11种模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、状态模式、策略模式、责任链模式、访问者模式、解释器模式和备忘录模式。 ??? 5.1、模板方法模式(Template Method Pattern):该模式注重对算法结构的封装,定义算法骨架,并且稳定,但是支持算法子步骤的变化。 ?????? 动机(Motivate):在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求? ?????? 意图(Intent):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 ?????? 具体结构图如下所示: ????????????? ??? 5.2、命令模式(Command Pattern):该模式注重将请求封装为对象,通过将一组行为抽象为对象,实现行为请求者和行为实现者之间的解耦。也可以实现“撤销/重做”的功能,类似“宏”的功能实现也很容易。 ?????? 动机(Motivate):在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比如需要对行为进行“记录、撤销/重做(undo/redo)、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。 ?????? 意图(Intent):将一个请求封装为一个对象,从而使你可用不同的请求对客户(客户程序,也是行为的请求者)进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。命令模式的实现可以提供命令的撤销和恢复功能。 ?????? 具体结构图如下所示: ???????????? ?????? 代码实例: 79 }
??? 5.4、观察者模式(Observer Pattern):该模式注重的是变化通知,变化通知指目标对象发生变化,依赖的对象就能获得通知并进行相应操作,这是一种“一对多”的关系。 ?????? 动机(Motivate):在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。 ?????? 意图(Intent):定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。 ?????? 具体结构图如下所示: ?????????????? ??? 5.5、中介者模式(Mediator Pattern):该模式注重封装对象间的交互,通过封装一系列对象之间的复杂交互,使他们不需要显式相互引用,实现解耦。 ?????? 动机(Motivate):在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断地变化。在这种情况下,我们可使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好地抵御变化。 ?????? 意图(Intent):定义了一个中介对象来封装一系列对象之间的交互关系。中介者使各个对象之间不需要显式地相互引用,从而使耦合性降低,而且可以独立地改变它们之间的交互行为。 ?????? 具体的结构图如下所示: ??????????? ?????? 代码实例: 1 中介者模式的实现 2 3 抽象中介者角色 4 interface Mediator 5 Command(Department department); 8 9 总经理--相当于具体中介者角色 10 President : Mediator 11 12 总经理有各个部门的管理权限 13 Financial _financial; 14 Market _market; 15 Development _development; 17 SetFinancial(Financial financial) 18 19 this._financial = financial; 21 SetDevelopment(Development development) 23 this._development = development; 25 SetMarket(Market market) 27 this._market = market; 28 29 30 Command(Department department) 31 32 if (department.GetType() == typeof(Market)) 33 34 _financial.Process(); 35 36 37 38 39 同事类的接口 40 Department 41 42 持有中介者(总经理)的引用 43 Mediator mediator; 44 45 Department(Mediator mediator) 46 47 this.mediator = mediator; 48 49 50 Mediator GetMediator 51 52 get { mediator; } 53 set { value; } 54 55 56 做本部门的事情 58 59 向总经理发出申请 60 Apply(); 62 63 开发部门 64 Development : Department 66 public Development(Mediator m) : (m) { } 67 68 69 70 Console.WriteLine(我们是开发部门,要进行项目开发,没钱了,需要资金支持! 71 72 73 Apply() 75 Console.WriteLine(专心科研,开发项目! 76 78 79 财务部门 80 Financial : Department 81 82 public Financial(Mediator m) : 83 84 86 Console.WriteLine(汇报工作!没钱了,钱太多了!怎么花? 87 88 89 90 91 Console.WriteLine(数钱! 92 93 94 95 市场部门 96 Market : Department 98 public Market(Mediator mediator) : (mediator) { } 99 100 101 102 Console.WriteLine(汇报工作!项目承接的进度,需要资金支持!103 GetMediator.Command(105 106 107 108 Console.WriteLine(跑去接项目!110 111 112 113 114 115 Main(String[] args) 116 117 President mediator = President(); 118 Market market = Market(mediator); 119 Development development = Development(mediator); 120 Financial financial = Financial(mediator); 121 122 mediator.SetFinancial(financial); 123 mediator.SetDevelopment(development); 124 mediator.SetMarket(market); 125 market.Process(); 127 market.Apply(); 128 129 130 132 }
?????? 代码实例: 状态模式的实现 3 环境角色---相当于Context类型 4 Order 6 State current; 7 Order() 10 工作状态初始化为上午工作状态 11 current = WaitForAcceptance(); 12 IsCancel = false; 14 double minute; 15 Minute 16 17 minute; } 18 set { minute = 19 20 21 bool IsCancel { get; set; } 22 bool finish; 24 TaskFinished 26 finish; } 27 set { finish = 29 SetState(State s) 30 31 current = s; 33 Action() 35 current.Process( 39 抽象状态角色---相当于State类型 40 State 42 处理订单 43 Process(Order order); 45 46 等待受理--相当于具体状态角色 47 WaitForAcceptance : State 49 Process(Order order) 50 51 System.Console.WriteLine(我们开始受理,准备备货! 52 if (order.Minute < 30 && order.IsCancel) 54 System.Console.WriteLine(接受半个小时之内,可以取消订单! 55 order.SetState( CancelOrder()); 56 order.TaskFinished = true 57 order.Action(); 58 59 order.SetState( AcceptAndDeliver()); 60 order.TaskFinished = order.Action(); 62 63 64 65 受理发货---相当于具体状态角色 AcceptAndDeliver : State 68 70 System.Console.WriteLine(我们货物已经准备好,可以发货了,不可以撤销订单! 71 72 73 System.Console.WriteLine( 74 order.SetState( 75 order.TaskFinished = 78 if (order.TaskFinished== 80 order.SetState( Success()); 82 84 85 86 交易成功---相当于具体状态角色 87 Success : State 88 89 91 System.Console.WriteLine(订单结算 92 order.SetState( ConfirmationReceipt()); 93 order.TaskFinished = 94 96 97 确认收货---相当于具体状态角色 99 ConfirmationReceipt : State 100 101 102 103 System.Console.WriteLine(检查货物,没问题可以就可以签收!104 order.SetState(105 order.TaskFinished = 106 108 109 110 取消订单---相当于具体状态角色 111 CancelOrder : State 112 113 115 System.Console.WriteLine(检查货物,有问题,取消订单!116 order.SetState(117 order.TaskFinished = 118 119 122 123 125 127 订单 128 Order order = Order(); 129 order.Minute = 9131 可以取消订单 132 order.IsCancel = 133 order.Minute = 20134 135 order.Minute = 33136 137 order.Minute = 43138 139 140 Console.Read(); 141 143 }
??? 5.8、责任链模式(Chain of Responsibility Pattern):该模式注重封装对象责任,支持责任的变化,通过动态构建职责链,实现业务处理。在现实生活中,请假流程,采购流程等都是职责链模式很好的例子。 ?????? 动机(Motivate):在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合。如何使请求的发送者不需要指定具体的接受者,让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。 ?????? 意图(Intent):避免请求发送者与接收者耦合在一起,让多个对象都有可能接受请求,将这些对象连接成一条链,并且沿着这条链传递请求,知道有对象处理它为止。 ?????? 具体结构图如下所示: ???????????? ??? 5.9、访问者模式(Visitor Pattern):该模式注重封装对象操作变化,支持在运行时为类结构添加新的操作,在类层次结构中,在不改变各类的前提下定义作用于这些类实例的新的操作。 ?????? 动机(Motivate):在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题? ?????? 意图(Intent):表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。 ?????? 具体结构图如下所示: ???????????? ?????? 代码实例: Vistor 抽象图形定义---相当于“抽象节点角色”Element Shape 画图形 7 Draw(); 8 外界注入具体访问者 9 Accept(ShapeVisitor visitor); 10 11 12 抽象访问者 Visitor 13 ShapeVisitor Visit(Rectangle shape); Visit(Circle shape); 18 19 Visit(Line shape); 这里有一点要说:Visit方法的参数可以写成Shape吗?就是这样 Visit(Shape shape),当然可以,但是ShapeVisitor子类Visit方法就需要判断当前的Shape是什么类型,是Rectangle类型,是Circle类型,或者是Line类型。 23 24 具体访问者 ConcreteVisitor 25 CustomVisitor : ShapeVisitor 27 针对Rectangle对象 28 Visit(Rectangle shape) 29 30 Console.WriteLine(针对Rectangle新的操作! 32 针对Circle对象 33 Visit(Circle shape) 35 Console.WriteLine(针对Circle新的操作! 37 针对Line对象 38 Visit(Line shape) 39 40 Console.WriteLine(针对Line新的操作! 42 43 44 矩形----相当于“具体节点角色” ConcreteElement 45 Rectangle : Shape Draw() 49 Console.WriteLine(矩形我已经画好! 51 52 Accept(ShapeVisitor visitor) 54 visitor.Visit( 56 57 58 圆形---相当于“具体节点角色”ConcreteElement 59 Circle : Shape 60 61 63 Console.WriteLine(圆形我已经画好! 64 65 68 visitor.Visit( 70 71 72 直线---相当于“具体节点角色” ConcreteElement Line : Shape 75 77 Console.WriteLine(直线我已经画好! 78 79 80 82 visitor.Visit( 86 结构对象角色 87 internal AppStructure ShapeVisitor _visitor; 90 91 AppStructure(ShapeVisitor visitor) 93 this._visitor = visitor; 95 96 Process(Shape shape) shape.Accept(_visitor); 99 101 102 103 104 105 106 如果想执行新增加的操作 107 ShapeVisitor visitor = CustomVisitor(); 108 AppStructure app = AppStructure(visitor); 110 Shape shape = Rectangle(); 111 shape.Draw();执行自己的操作 112 app.Process(shape);执行新的操作 113 114 115 shape = Circle(); 116 shape.Draw();117 app.Process(shape);118 119 120 shape = Line(); 121 shape.Draw();122 app.Process(shape);123 124 125 Console.ReadLine(); 128 }
?????? 代码实例: MementoPattern 联系人--需要备份的数据,是状态数据,没有操作 ContactPerson 姓名 string Name { 电话号码 10 string MobileNumber { 12 发起人--相当于【发起人角色】Originator 14 MobileBackOriginator 16 发起人需要保存的内部状态 private List<ContactPerson> _personList; 19 20 public List<ContactPerson> ContactPersonList 22 get 24 ._personList; 26 set 29 this._personList = value; 初始化需要备份的电话名单 public MobileBackOriginator(List<ContactPerson> personList) 35 if (personList != 37 personList; 39 else 40 41 throw new ArgumentNullException(参数不能为空! 43 创建备忘录对象实例,将当期要保存的联系人列表保存到备忘录对象中 ContactPersonMemento CreateMemento() 48 new ContactPersonMemento(new List<ContactPerson>(._personList)); 50 51 将备忘录中的数据备份还原到联系人列表中 RestoreMemento(ContactPersonMemento memento) 54 this.ContactPersonList = memento.ContactPersonListBack; 56 Show() 59 Console.WriteLine(联系人列表中共有{0}个人,他们是:,ContactPersonList.Count); 60 foreach (ContactPerson p in ContactPersonList) 62 Console.WriteLine(姓名: {0} 号码: {1} 66 67 备忘录对象,用于保存状态数据,保存的是当时对象具体状态数据--相当于【备忘录角色】Memeto 68 ContactPersonMemento 70 保存发起人创建的电话名单数据,就是所谓的状态 71 public List<ContactPerson> ContactPersonListBack { public ContactPersonMemento(List<ContactPerson> 75 ContactPersonListBack = 管理角色,它可以管理【备忘录】对象,如果是保存多个【备忘录】对象,当然可以对保存的对象进行增、删等管理处理---相当于【管理者角色】Caretaker MementoManager 如果想保存多个【备忘录】对象,可以通过字典或者堆栈来保存,堆栈对象可以反映保存对象的先后顺序 83 比如:public Dictionary<string,ContactPersonMemento> ContactPersonMementoDictionary { get; set; } public ContactPersonMemento ContactPersonMemento { 86 91 List<ContactPerson> persons = new List<ContactPerson>() 93 new ContactPerson() { Name=黄飞鸿",MobileNumber = 13533332222}, 94 方世玉13966554433 95 洪熙官13198765544} }; 98 手机名单发起人 99 MobileBackOriginator mobileOriginator = MobileBackOriginator(persons); mobileOriginator.Show(); 102 创建备忘录并保存备忘录对象 103 MementoManager manager = MementoManager(); 104 manager.ContactPersonMemento = mobileOriginator.CreateMemento(); 更改发起人联系人列表 107 Console.WriteLine(----移除最后一个联系人--------108 mobileOriginator.ContactPersonList.RemoveAt(2110 111 恢复到原始状态 112 Console.WriteLine(-------恢复联系人列表------113 mobileOriginator.RestoreMemento(manager.ContactPersonMemento); 115 117 119 }
六、总结 ??? C#版本23种面向对象的设计模式,终于写完了,今天是一个总结性的文章。各个模式都列了出来,每个模式的【动机】、【意图】和【结构图】也写了出来,可以方便大家查看。重新自己写了一遍,感觉很多都不一样了。理解更深刻了,学无止境,继续前进吧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |