当对象拥有不同的状态,往往会导致行为不同。在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?
意图
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。
结构图

话说,状态的改变也能用if-else 来完成逻辑演绎,但如果系统中增添了新的状态,则耦合的代码,就显得疲惫不堪了。如果状态很多,程序员自己也很难维护。这里的state 模式,将状态改变时影响的行为抽象到一个类里,用一个个具体的子类来表达不同的状态,从而很好的封装了变化点。
代码
using System;
namespace State
{
class Program
{
static void Main(string[] args)
{
Document doc = new Document();
Editable edit = new Editable();
Insert ins = new Insert();
edit.NextState = ins;
doc.SetState(edit);
doc.Handle();
//查看轮换后的效果
doc.Handle();
}
}
abstract class StatedWithDocument {
StatedWithDocument nextState;
public StatedWithDocument NextState
{
get { return nextState; }
set { nextState = value; }
}
public abstract void Handle();
}
class Document {
StatedWithDocument state;
public void SetState(StatedWithDocument state) {
this.state = state;
}
public void Handle() {
this.state.Handle();
//也许需要轮换
this.state = this.state.NextState;
}
}
class Editable : StatedWithDocument {
public override void Handle() {
Console.WriteLine("Now,I'm Editable...");
}
}
class Insert : StatedWithDocument {
public override void Handle() {
Console.WriteLine("Now,I'm Insertable...");
}
}
}
运行结果

在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。
如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
结构图

其实结构图中Caretaker 不一定必须实现,不难发现的是,他是对“备忘录”中保存的状态的起到一种暂存的作用。下面是一段代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Memento
{
class Program
{
static void Main(string[] args)
{
Person A = new Person("A");
Person B = new Person("B");
Person C = new Person("C");
HRSystem hr = new HRSystem();
hr.Add(A);
hr.Add(B);
Memento m = hr.CreatMemento();
hr.Add(C);
Console.WriteLine("After added C, we have :");
hr.ShowInfo();
Console.WriteLine("But, I've made a mistake...So:");
hr.RecoverToMemento(m);
hr.ShowInfo();
}
}
[Serializable]
class Person {
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Person(string name) {
this.name = name;
}
}
[Serializable]
class HRSystem {
List list = new List();
public void ShowInfo() {
Console.WriteLine("-----------------");
foreach (Person p in list) {
Console.WriteLine("{0} is available .",p.Name);
}
Console.WriteLine("-----------------");
}
public void Add(Person p) {
if (list != null && !list.Contains(p)) {
list.Add(p);
Console.WriteLine("{0} has been added!", p.Name);
}
}
public void Remove(Person p) {
if (list != null && list.Contains(p)) {
Console.WriteLine("{0} has been removed!",p.Name);
}
}
public void SetHRList(HRSystem hr) {
this.list = hr.list;
}
public Memento CreatMemento() {
Console.WriteLine("Now ,Saving State above ↑...");
return new Memento().SetMemento(this);
}
public void RecoverToMemento(Memento m) {
Console.WriteLine("Recovering To Memento...");
HRSystem hr = (HRSystem)m.GetMemento();
this.SetHRList(hr);
}
}
class Memento {
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
public Memento SetMemento(object obj) {
bf.Serialize(ms,obj);
return this;
}
public object GetMemento() {
ms.Seek(0,SeekOrigin.Begin);
return bf.Deserialize(ms);
}
}
}
运行截图

在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显式指定,将必不可少地带来请求发送者与接受者的紧耦合。如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。
意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
结构图
职责链模式在其内部实现了一个自我的链式结构,采用了和Decorator 模式一样的方法,不但继承了自己,还要包含自己。下面的代码,模拟了一个公司处理订单的业务逻辑,多少金额内,什么级别的人可以处理。
代码
using System;
namespace Chain_of_Responsibility
{
class Program
{
static void Main(string[] args)
{
Purchase p = new Purchase(2012,9678.89,"Diamond For Women");
President president = new President();
VicePresident vicepresident = new VicePresident("Nobody-Care", president);
Director director = new Director("Impp", vicepresident);
director.ProcessRequest(p);
p = new Purchase(2013, 159678.00, "Car For Women");
director.ProcessRequest(p);
p = new Purchase(2014, 459678.00, "House For Women");
director.ProcessRequest(p);
}
}
class Purchase {
private int _number;
public int Number
{
get { return _number; }
set { _number = value; }
}
private double _amount;
public double Amount
{
get { return _amount; }
set { _amount = value; }
}
private string _purpose;
public string Purpose
{
get { return _purpose; }
set { _purpose = value; }
}
public Purchase(int number,double amount,string purpose) {
this._amount = amount;
this._number = number;
this._purpose = purpose;
}
}
abstract class Approver {
protected Approver _successor;
internal Approver Successor
{
get { return _successor; }
set { _successor = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public Approver(string name,Approver successor) {
this._name = name;
this._successor = successor;
}
public virtual void ProcessRequest(Purchase p) {
if (this._successor != null) {
this._successor.ProcessRequest(p);
}
}
}
class Director : Approver {
public Director(string name, Approver successor) : base(name, successor) { }
public Director() : base("Director", null) { }
public override void ProcessRequest(Purchase p) {
if (p.Amount < 10000) {
Console.WriteLine("{0} approved reqest #{1}",this.GetType().Name,p.Number);
}
else
base.ProcessRequest(p);
}
}
class VicePresident : Approver {
public VicePresident(string name, Approver successor) : base(name, successor) { }
public VicePresident() : base("Director", null) { }
public override void ProcessRequest(Purchase p) {
if(p.Amount<200000){
Console.WriteLine("{0} approved reqest #{1}", this.GetType().Name, p.Number);
}
else
base.ProcessRequest(p);
}
}
class President : Approver {
public President(string name, Approver successor) : base(name, successor) { }
public President() : base("Director", null) { }
public override void ProcessRequest(Purchase p) {
if (p.Amount < 500000) {
Console.WriteLine("{0} approved reqest #{1}", this.GetType().Name, p.Number);
}
else
Console.WriteLine("Request #{0} needs an excutive meeting!",p.Number);
}
}
}
运行结果

观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
结构图
从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以有任意多个对抽象观察者对象的引用。之所以使用抽象观察者而不是具体观察者,意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要的时候调用每一个观察者共有的Update()方法。这种做法叫做”面向接口编程”。
实际上在C#中实现Observer模式没有这么辛苦,.NET中提供了Delegate与Event机制,我们可以利用这种机制简化Observer模式。下面我会用一段代码同时演示2种模式。
代码
using System;
using System.Collections.Generic;
namespace Observer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("------------------------------");
Console.WriteLine("使用观察者模式:");
Email e = new Email();
Mobole m = new Mobole();
Microsoft ms = new Microsoft();
ms.Add(e);
ms.Add(m);
ms.Price = 50;
Console.WriteLine();
Google g = new Google();
g.Add(e); g.Add(m);
g.Price = 220;
Console.WriteLine("------------------------------");
Console.WriteLine("使用Event 模式:");
Google g2 = new Google();
g2.priceChange += e.Update;
g2.Price = 300;
Microsoft m2 = new Microsoft();
m2.priceChange += m.Update;
m2.Price = 100;
}
}
public interface IObserver {
void Update(string symbol,decimal price);
}
public delegate void PriceChangeHandler(string symbol,decimal price);
abstract class Stock {
private string _symbol;
private decimal _price;
protected List list = new List();
public event PriceChangeHandler priceChange;
public decimal Price {
get { return _price; }
set {
_price = value;
this.Notify(this._symbol,this._price);
this.OnChange(this._symbol, this._price);
}
}
void OnChange(string symbol,decimal price) {
if (priceChange != null)
priceChange(symbol,price);
}
public Stock(string sysbol,decimal price) {
this._price = price;
this._symbol = sysbol;
}
public void Add(IObserver ob) {
list.Add(ob);
}
public void Remove(IObserver ob) {
list.Add(ob);
}
protected virtual void Notify(string symbol, decimal price) {
foreach (IObserver ob in list)
ob.Update(symbol, price);
}
}
class Microsoft:Stock {
public Microsoft():base("Microsoft",120) { }
}
class Google : Stock {
public Google() : base("Google", 200) { }
}
class Email:IObserver {
public void Update(string symbol,decimal price) {
Console.WriteLine("尊敬的客户,您使用Email 订阅了{0} 的股票,它的最新价格为 {1}!",symbol,price);
}
}
class Mobole : IObserver {
public void Update(string symbol, decimal price) {
Console.WriteLine("尊敬的客户,您使用Mobile 订阅了{0} 的股票,它的最新价格为 {1}!", symbol, price);
}
}
}
运行结果

最近评论