设计模式--行为型模式
记录模式的一个最好方法是,朝着正在编写的代码需要的方向去演化代码,当重构代码以解决耦合性、简单性以及表达性的问题时,可能就发现代码已经接近于一个模式了。
命令模式
意图:
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队下载或记录请求日志,以及支持可撤消的操作。
适用性:
- 抽象出待执行的动作以参数化某对象。你可用过程语言中的回调(callback)函数表达这种参数化机制。
- UnDo()操作
- 可以在突发情况下通过存储的命令再次执行一遍用以还原系统。
- 如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
参与者:
- • C o m m a n d
— 声明执行操作的接口。
public interface Command
{
void execute();
void undo();
}
- • C o n c r e t e C o m m a n d ( P a s t e C o m m a n d,O p e n C o m m a n d )
— 将一个接收者对象绑定于一个动作。
— 调用接收者相应的操作,以实现E x e c u t e。
public class GarageDoorOpenCommand:Command
{
GarageDoor garageDoor;
public GarageDoorOpenCommand(GarageDoor garageDoor)
{
this.garageDoor = garageDoor;
}
public void execute()
{
garageDoor.up();
}
public void undo()
{
garageDoor.up();
}
}
- • C l i e n t ( A p p l i c t i o n )
— 创建一个具体命令对象并设定它的接收者。
static void Main(string[] args)
{
SimpleRemoteControl remote = new SimpleRemoteControl();
Light light = new Light();
LightOnCommand lightOn = new LightOnCommand(light);
remote.setCommand(lightOn);
remote.buttonWasPressed();
Console.Read();
}
- • Invoker ( M e n u I t e m )
— 要求该命令执行这个请求。
public class SimpleRemoteControl
{
Command slot;
public SimpleRemoteControl()
{ }
/// <summary>
/// 设置插槽控制的命令 Invoker
/// </summary>
/// <param name="command"></param>
public void setCommand(Command command)
{
slot = command;
}
/// <summary>
/// 当前命令衔接插槽,并调用他的execute()方法
/// </summary>
public void buttonWasPressed()
{
slot.execute();
}
}
- • R e c e i v e r ( D o c u m e n t,A p p l i c a t i o n )
— 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
public class Light
{
public void on()
{
Console.WriteLine("Light is On");
}
public void off()
{
Console.WriteLine("Light is Off");
}
}
观察者模式(发布订阅)
意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
适用性:
- 一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。
- 可以在突发情况下通过存储的命令再次执行一遍用以还原系统。
- 如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
- 推模式与拉模式:当需要主题传输给所有观察者的时候,消息一致并且所有观察者都需要的情况下,可以使用推模式;如果观察者需要按需索取相应信息时,或者当通知消息的参数有变化时,不是所有的观察者对象都要变化的情况下。则应该使用拉模式。
参与者:
- • S u b j e c t(目标)
— 目标知道它的观察者。可以有任意多个观察者观察同一个目标。
— 提供注册和删除观察者对象的接口。
/// <summary>
/// 主题接口
/// </summary>
public interface Subject
{
/// <summary>
/// 注册
/// </summary>
/// <param name="o">用观察者做变量</param>
void registerObserver(Observer o);
/// <summary>
/// 移除
/// </summary>
/// <param name="o">用观察者做变量</param>
void removeObserver(Observer o);
/// <summary>
/// 状态改变时通知观察者
/// </summary>
void notifyObservers();
}
- • O b s e r v e r(观察者)
— 为那些在目标发生改变时需获得通知的对象定义一个更新接口。
public interface Observer
{
/// <summary>
/// 气象值进行变化(方法感觉有问题,如果观察种类,个数存在变化时,变动比较多)
/// </summary>
/// <param name="temp"></param>
/// <param name="humidity"></param>
/// <param name="pressure"></param>
void Update(float temp, float humidity, float pressure);
}
- • C o n c r e t e S u b j e c t(具体目标)
— 将有关状态存入各C o n c r e t e O b s e r v e r对象。
— 当它的状态发生改变时, 向它的各个观察者发出通知。
/// <summary>
/// 从气象站获取数据
/// </summary>
public class WeatherData:Subject
{
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData()
{
observers = new ArrayList();
}
public void registerObserver(Observer o)
{
observers.Add(o);
}
public void removeObserver(Observer o)
{
int i = observers.IndexOf(o);
if (i > 0)
{
observers.Remove(i);
}
}
/// <summary>
/// 更新的操作
/// </summary>
/// <param name="o"></param>
public void notifyObservers()
{
for (int i = 0; i < observers.Count; i++)
{
Observer observer = (Observer)observers[i];
observer.Update(temperature, humidity, pressure);
}
}
/// <summary>
/// 通知观察者
/// </summary>
public void measurementsChanged()
{
notifyObservers();
}
public void setMeasurements(float temp, float humidity, float pressure)
{
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
- • C o n c r e t e O b s e r v e r(具体观察者)
— 维护一个指向C o n c r e t e S u b j e c t对象的引用。
— 存储有关状态,这些状态应与目标的状态保持一致。
— 实现O b s e r v e r的更新接口以使自身状态与目标的状态保持一致。
/// <summary>
/// 显示天气预报
/// </summary>
public class ForecastDisplay : Observer, DisplayElement
{
private float temperature;
private float humidity;
private Subject weatherData;
/// <summary>
/// 构造器需要weatherData对象(主题)作为注册之用
/// </summary>
/// <param name="weatherData"></param>
public ForecastDisplay(Subject weatherData)
{
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void Update(float temp, float humidity, float pressure)
{
this.temperature = temp;
this.humidity = humidity;
display();
}
public void display()
{
Console.WriteLine(string.Format(" 天气预报:{0}, 适度{1}!", temperature, humidity));
}
}

浙公网安备 33010602011771号