OOAD之设计模式-行为模式

时间:2023-02-24 11:41:58

一、行为模式

行为模式关注的是对象的行为。该类型的模式需要做的是对可能变化的行为进行抽象,通过封装达到整个架构的可扩展性。例如策略模式,就是将可能变化的策略或算法抽象为一个独立的接口或抽象类,从而实现未来策略的扩展。其它的行为型设计模式也大致如此,或者封装一个请求(命令模式),或者封装一种状态(状态模式),或者封装访问的方式(访问者模式),或者封装遍历算法(迭代器模式)。这些模式所要封装的行为,恰恰是软件架构中最不稳定的部分,扩展的可能性也最大。将这些行为封装起来,利用抽象的特性,就提供了扩展的可能。
GOF模式中的行为型设计模式共有11种。其中,行为型类设计模式使用继承机制在类间分派行为,包括模板方法模式(Template Method)和解释器模式(Interpreter)共两种。行为型对象模式使用对象组合而不是继承,它描述一组对象怎样协作完成单个对象所无法完成的任务,包括责任链模式(Chain of Responsibility)、命令模式(Command)、迭代器模式(Iterator)、中介模式(Mediator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式(State)、策略模式(Strategy)、访问者模式(Visitor)九种。
 

1.1模板方法模式template method

已知过程的主要流程步骤,但是某些具体的实现未知时,抽象类控制具体流程,实现类实现具体的步骤细节。只用继承。

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法可以使子类可以不改变一个算法的结构即可以重定义该算法的某些特定步骤。

模板方法模式意图是由抽象父类控制*逻辑,并把基本操作的实现推迟到子类去实现,这是通过继承的手段来达到对象的复用,同时也遵守了开闭原则。 

把不变的行为搬到超类,去除子类中重复的代码来体现他的优势。

当不变的和可变的行为在方法中混合在一起时,不变的行为就会在子类中重复出现,模板方法模式就是将这些不变的行为搬移到一个超类中,避免重复代码。

OOAD之设计模式-行为模式

 

1.2策略模式strategy

业务中某个问题的算法太多,不同环境的实现不同,将该算法抽象为一个接口,在具体的使用类中用组合来调用。

定义一系列算法:策略模式的功能就是定义一系列算法,实现让这些算法可以相互替换。所以会为这一系列算法定义公共的接口,以约束一系列算法要实现的功能。

避免多重条件语句,更好的扩展性。

缺点:

客户必须了解每种策略的不同。

增加了对象数目。

只适合扁平的算法结构:策略模式的一系列算法地位是平等的,是可以相互替换的,事实上构成了一个扁平的算法结构,也就是在一个策略接口下,有多个平等的策略算法,就相当于兄弟算法。而且在运行时刻只有一个算法被使用,这就限制了算法使用的层级,使用的时候不能嵌套使用。对于出现需要嵌套使用多个算法的情况,比如折上折、折后返卷等业务的实现,需要组合或者是嵌套使用多个算法的情况,可以考虑使用装饰模式、或是变形的职责链、或是AOP等方式来实现。
 
适用范围:
出现有许多相关的类,仅仅是行为有差别的情况,可以使用策略模式来使用多个行为中的一个来配置一个类的方法,实现算法动态切换;
出现同一个算法,有很多不同的实现的情况,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次;
需要封装算法中,与算法相关的数据的情况,可以使用策略模式来避免暴露这些跟算法相关的数据结构;
出现抽象一个定义了很多行为的类,并且是通过多个if-else语句来选择这些行为的情况,可以使用策略模式来代替这些条件语句。
 

 

1.3观察者模式

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

效果及实现要点
 
1.使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到松耦合。
2.目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。观察者自己决定是否需要订阅通知。目标对象对此一无所知。
3.在C#中的Event。委托充当了抽象的Observer接口,而提供事件的对象充当了目标对象,委托是比抽象Observer接口更为松耦合的设计。
适用性
1.当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2.当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
 
[java] view plain copy
  1. public class Product extends Observable{  
  2.       
  3.     private String name;  
  4.       
  5.     private float price;  
  6.   
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.   
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14.   
  15.     public float getPrice() {  
  16.         return price;  
  17.     }  
  18.   
  19.     public void setPrice(float price) {  
  20.         this.setChanged();  
  21.         this.notifyObservers(price);  
  22.         this.price = price;  
  23.     }  
  24. }  
[java] view plain copy
  1. import java.util.Observable;  
  2. import java.util.Observer;  
  3.   
  4. public class PriceObserver implements Observer{  
  5.   
  6.     public void update(Observable o, Object arg) {  
  7.         // TODO Auto-generated method stub  
  8.         Product pro = (Product)o;  
  9.         if(pro.getPrice() > (Float)arg){  
  10.             System.out.println("降价:" + (pro.getPrice() - (Float)arg));  
  11.         }else if(pro.getPrice() < (Float)arg){  
  12.             System.out.println("涨价:" + ((Float)arg - pro.getPrice()));  
  13.         }  
  14.     }  
  15.   
  16. }  

 

1.4命令模式command

在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

目的:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

OOAD之设计模式-行为模式

效果及实现要点
1.Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”。
2.实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能会保存一些额外的状态信息。
3.通过使用Compmosite模式,可以将多个命令封装为一个“复合命令”MacroCommand。
4.Command模式与C#中的Delegate有些类似。但两者定义行为接口的规范有所区别:Command以面向对象中的“接口-实现”来定义行为接口规范,更严格,更符合抽象原则;Delegate以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱。
5.使用命令模式会导致某些系统有过多的具体命令类。某些系统可能需要几十个,几百个甚至几千个具体命令类,这会使命令模式在这样的系统里变得不实际。
适用性
在下面的情况下应当考虑使用命令模式:
1.使用命令模式作为"CallBack"在面向对象系统中的替代。"CallBack"讲的便是先将一个函数登记上,然后在以后调用此函数。
2.需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。
3.系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。

4.如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。


转自:http://blog.csdn.net/mudeer2012/article/details/8453560