0%

   在上一篇博文分享了访问者模式,访问者模式的实现是把作用于某种数据结构上的操作封装到访问者中,使得操作和数据结构隔离。而今天要介绍的备忘者模式与命令模式有点相似,不同的是,命令模式保存的是发起人的具体命令(命令对应的是行为),而备忘录模式保存的是发起人的状态(而状态对应的数据结构,如属性)。下面具体来看看备忘录模式。

2.1 备忘录模式的定义

   从字面意思就可以明白,备忘录模式就是对某个类的状态进行保存下来,等到需要恢复的时候,可以从备忘录中进行恢复。生活中这样的例子经常看到,如备忘电话通讯录,备份操作操作系统,备份数据库等。

  备忘录模式的具体定义是:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以把该对象恢复到原先的状态。

2.2 备忘录模式的结构图

   介绍完备忘录模式的定义之后,下面具体看看备忘录模式的结构图:

  备忘录模式中主要有三类角色:

  • 发起人角色:记录当前时刻的内部状态,负责创建和恢复备忘录数据。
  • 备忘录角色:负责存储发起人对象的内部状态,在进行恢复时提供给发起人需要的状态。
  • 管理者角色:负责保存备忘录对象。

2.3 备忘录模式的实现

   下面以备份手机通讯录为例子来实现了备忘录模式,具体的实现代码如下所示:

复制代码

// 联系人
public class ContactPerson
{ public string Name { get; set; } public string MobileNum { get; set; }
} // 发起人
public class MobileOwner
{ // 发起人需要保存的内部状态
public List ContactPersons { get; set; } public MobileOwner(List persons)
{
ContactPersons = persons;
} // 创建备忘录,将当期要保存的联系人列表导入到备忘录中
public ContactMemento CreateMemento()
{ // 这里也应该传递深拷贝,new List方式传递的是浅拷贝,
// 因为ContactPerson类中都是string类型,所以这里new list方式对ContactPerson对象执行了深拷贝
// 如果ContactPerson包括非string的引用类型就会有问题,所以这里也应该用序列化传递深拷贝
return new ContactMemento(new List(this.ContactPersons));
} // 将备忘录中的数据备份导入到联系人列表中
public void RestoreMemento(ContactMemento memento)
{ // 下面这种方式是错误的,因为这样传递的是引用,
// 则删除一次可以恢复,但恢复之后再删除的话就恢复不了.
// 所以应该传递contactPersonBack的深拷贝,深拷贝可以使用序列化来完成
this.ContactPersons = memento.contactPersonBack;
} public void Show()
{
Console.WriteLine(“联系人列表中有{0}个人,他们是:”, ContactPersons.Count); foreach (ContactPerson p in ContactPersons)
{
Console.WriteLine(“姓名: {0} 号码为: {1}”, p.Name, p.MobileNum);
}
}
} // 备忘录
public class ContactMemento
{ // 保存发起人的内部状态
public List contactPersonBack; public ContactMemento(List persons)
{
contactPersonBack = persons;
}
} // 管理角色
public class Caretaker
{ public ContactMemento ContactM { get; set; }
} class Program
{ static void Main(string[] args)
{
List persons = new List()
{ new ContactPerson() { Name= “Learning Hard”, MobileNum = “123445”}, new ContactPerson() { Name = “Tony”, MobileNum = “234565”}, new ContactPerson() { Name = “Jock”, MobileNum = “231455”}
};
MobileOwner mobileOwner = new MobileOwner(persons);
mobileOwner.Show(); // 创建备忘录并保存备忘录对象
Caretaker caretaker = new Caretaker();
caretaker.ContactM = mobileOwner.CreateMemento(); // 更改发起人联系人列表
Console.WriteLine(“-—移除最后一个联系人——–”);
mobileOwner.ContactPersons.RemoveAt(2);
mobileOwner.Show(); // 恢复到原始状态
Console.WriteLine(“-——恢复联系人列表——“);
mobileOwner.RestoreMemento(caretaker.ContactM);
mobileOwner.Show();

        Console.Read();
    }
}

复制代码

  具体的运行结果如下图所示:

  从上图可以看出,刚开始通讯录中有3个联系人,然后移除以后一个后变成2个联系人了,最后恢复原来的联系人列表后,联系人列表中又恢复为3个联系人了。

  上面代码只是保存了一个还原点,即备忘录中只保存了3个联系人的数据,但是,如果想备份多个还原点怎么办呢?即恢复到3个人后,又想恢复到前面2个人的状态,这时候可能你会想,这样没必要啊,到时候在删除不就好了。但是如果在实际应用中,可能我们发了很多时间去创建通讯录中只有2个联系人的状态,恢复到3个人的状态后,发现这个状态时错误的,还是原来2个人的状态是正确的,难道我们又去花之前的那么多时间去重复操作吗?这显然不合理,如果就思考,能不能保存多个还原点呢?保存多个还原点其实很简单,只需要保存多个备忘录对象就可以了。具体实现代码如下所示:

复制代码

namespace MultipleMementoPattern
{ // 联系人
public class ContactPerson
{ public string Name { get; set; } public string MobileNum { get; set; }
} // 发起人
public class MobileOwner
{ public List ContactPersons { get; set; } public MobileOwner(List persons)
{
ContactPersons = persons;
} // 创建备忘录,将当期要保存的联系人列表导入到备忘录中
public ContactMemento CreateMemento()
{ // 这里也应该传递深拷贝,new List方式传递的是浅拷贝,
// 因为ContactPerson类中都是string类型,所以这里new list方式对ContactPerson对象执行了深拷贝
// 如果ContactPerson包括非string的引用类型就会有问题,所以这里也应该用序列化传递深拷贝
return new ContactMemento(new List(this.ContactPersons));
} // 将备忘录中的数据备份导入到联系人列表中
public void RestoreMemento(ContactMemento memento)
{ if (memento != null)
{ // 下面这种方式是错误的,因为这样传递的是引用,
// 则删除一次可以恢复,但恢复之后再删除的话就恢复不了.
// 所以应该传递contactPersonBack的深拷贝,深拷贝可以使用序列化来完成
this.ContactPersons = memento.ContactPersonBack;
}
} public void Show()
{
Console.WriteLine(“联系人列表中有{0}个人,他们是:”, ContactPersons.Count); foreach (ContactPerson p in ContactPersons)
{
Console.WriteLine(“姓名: {0} 号码为: {1}”, p.Name, p.MobileNum);
}
}
} // 备忘录
public class ContactMemento
{ public List ContactPersonBack {get;set;} public ContactMemento(List persons)
{
ContactPersonBack = persons;
}
} // 管理角色
public class Caretaker
{ // 使用多个备忘录来存储多个备份点
public Dictionary<string, ContactMemento> ContactMementoDic { get; set; } public Caretaker()
{
ContactMementoDic = new Dictionary<string, ContactMemento>();
}
} class Program
{ static void Main(string[] args)
{
List persons = new List()
{ new ContactPerson() { Name= “Learning Hard”, MobileNum = “123445”}, new ContactPerson() { Name = “Tony”, MobileNum = “234565”}, new ContactPerson() { Name = “Jock”, MobileNum = “231455”}
};

        MobileOwner mobileOwner \= new MobileOwner(persons);
        mobileOwner.Show(); // 创建备忘录并保存备忘录对象
        Caretaker caretaker = new Caretaker();
        caretaker.ContactMementoDic.Add(DateTime.Now.ToString(), mobileOwner.CreateMemento()); // 更改发起人联系人列表
        Console.WriteLine("\----移除最后一个联系人--------");
        mobileOwner.ContactPersons.RemoveAt(2);
        mobileOwner.Show(); // 创建第二个备份
        Thread.Sleep(1000);
        caretaker.ContactMementoDic.Add(DateTime.Now.ToString(), mobileOwner.CreateMemento()); // 恢复到原始状态
        Console.WriteLine("\-------恢复联系人列表,请从以下列表选择恢复的日期------"); var keyCollection = caretaker.ContactMementoDic.Keys; foreach (string k in keyCollection)
        {
            Console.WriteLine("Key = {0}", k);
        } while (true)
        {
            Console.Write("请输入数字,按窗口的关闭键退出:"); int index = -1; try {
                index \= Int32.Parse(Console.ReadLine());
            } catch {
                Console.WriteLine("输入的格式错误"); continue;
            }
            
            ContactMemento contactMentor \= null; if (index < keyCollection.Count && caretaker.ContactMementoDic.TryGetValue(keyCollection.ElementAt(index), out contactMentor))
            {
                mobileOwner.RestoreMemento(contactMentor);
                mobileOwner.Show();
            } else {
                Console.WriteLine("输入的索引大于集合长度!");
            }
        }     
    }
}

}

复制代码

  这样就保存了多个状态,客户端可以选择恢复的状态点,具体运行结果如下所示:

   在以下情况下可以考虑使用备忘录模式:

  • 如果系统需要提供回滚操作时,使用备忘录模式非常合适。例如文本编辑器的Ctrl+Z撤销操作的实现,数据库中事务操作。

   备忘录模式具有以下优点:

  • 如果某个操作错误地破坏了数据的完整性,此时可以使用备忘录模式将数据恢复成原来正确的数据。
  • 备份的状态数据保存在发起人角色之外,这样发起人就不需要对各个备份的状态进行管理。而是由备忘录角色进行管理,而备忘录角色又是由管理者角色管理,符合单一职责原则。

  当然,备忘录模式也存在一定的缺点:

  • 在实际的系统中,可能需要维护多个备份,需要额外的资源,这样对资源的消耗比较严重。

  备忘录模式主要思想是——利用备忘录对象来对保存发起人的内部状态,当发起人需要恢复原来状态时,再从备忘录对象中进行获取,在实际开发过程也应用到这点,例如数据库中的事务处理。

一、引言

在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中分配了多个一样的类实例对象,然后如果采用工厂模式来创建这样的系统的话,随着产品类的不断增加,导致子类的数量不断增多,反而增加了系统复杂程度,所以在这里使用工厂模式来封装类创建过程并不合适,然而原型模式可以很好地解决这个问题,因为每个类实例都是相同的,当我们需要多个相同的类实例时,没必要每次都使用new运算符去创建相同的类实例对象,此时我们一般思路就是想——只创建一个类实例对象,如果后面需要更多这样的实例,可以通过对原来对象拷贝一份来完成创建,这样在内存中不需要创建多个相同的类实例,从而减少内存的消耗和达到类实例的复用。 然而这个思路正是原型模式的实现方式。下面就具体介绍下设计模式中的原型设计模式。

二、原型模式的详细介绍

在现实生活中,也有很多原型设计模式的例子,例如,细胞分裂的过程,一个细胞的有丝分裂产生两个相同的细胞;还有西游记中孙悟空变出后孙的本领和火影忍者中鸣人的隐分身忍术等。下面就以孙悟空为例子来演示下原型模式的实现。具体的实现代码如下:

复制代码

///火影忍者中鸣人的影分身和孙悟空的的变都是原型模式
class Client
{ static void Main(string[] args)
{ // 孙悟空 原型
MonkeyKingPrototype prototypeMonkeyKing = new ConcretePrototype(“MonkeyKing”); // 变一个
MonkeyKingPrototype cloneMonkeyKing = prototypeMonkeyKing.Clone() as ConcretePrototype;
Console.WriteLine(“Cloned1:\t”+cloneMonkeyKing.Id); // 变两个
MonkeyKingPrototype cloneMonkeyKing2 = prototypeMonkeyKing.Clone() as ConcretePrototype;
Console.WriteLine(“Cloned2:\t” + cloneMonkeyKing2.Id);
Console.ReadLine();
}
} ///


/// 孙悟空原型 ///

public abstract class MonkeyKingPrototype
{ public string Id { get; set; } public MonkeyKingPrototype(string id)
{ this.Id = id;
} // 克隆方法,即孙大圣说“变”
public abstract MonkeyKingPrototype Clone();
} ///
/// 创建具体原型 ///

public class ConcretePrototype : MonkeyKingPrototype
{ public ConcretePrototype(string id)
: base(id)
{ } ///
/// 浅拷贝 ///

///
public override MonkeyKingPrototype Clone()
{ // 调用MemberwiseClone方法实现的是浅拷贝,另外还有深拷贝
return (MonkeyKingPrototype)this.MemberwiseClone();
}
}

复制代码

上面原型模式的运行结果为(从运行结果可以看出,创建的两个拷贝对象的ID属性都是与原型对象ID属性一样的):

上面代码实现的浅拷贝的方式,浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么这两个对象将引用同一个字符串,而深拷贝是对对象实例中字段引用的对象也进行拷贝,如果一个对象有一个指向字符串的字段,并且我们对该对象进行了深拷贝的话,那么我们将创建一个对象和一个新的字符串,新的对象将引用新的字符串。也就是说,执行深拷贝创建的新对象和原来对象不会共享任何东西,改变一个对象对另外一个对象没有任何影响,而执行浅拷贝创建的新对象与原来对象共享成员,改变一个对象,另外一个对象的成员也会改变。

介绍完原型模式的实现代码之后,下面看下原型模式的类图,通过类图来理清原型模式实现中类之间的关系。具体类图如下:

三、原型模式的优缺点

原型模式的优点有:

  1. 原型模式向客户隐藏了创建新实例的复杂性
  2. 原型模式允许动态增加或较少产品类。
  3. 原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。
  4. 产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构

原型模式的缺点有:

  1. 每个类必须配备一个克隆方法
  2. 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

四、.NET中原型模式的实现

在.NET中可以很容易地通过实现ICloneable接口(这个接口就是原型,提供克隆方法,相当于与上面代码中MonkeyKingPrototype抽象类)中Clone()方法来实现原型模式,如果我们想我们自定义的类具有克隆的功能,首先定义类继承与ICloneable接口并实现Clone方法。在.NET中实现了原型模式的类如下图所示(图中只截取了部分,可以用Reflector反编译工具进行查看):

五、总结

到这里关于原型模式的介绍就结束了,原型模式用一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的方法来创建出更多的同类型对象,它与工厂方法模式的实现非常相似,其中原型模式中的Clone方法就类似工厂方法模式中的工厂方法,只是工厂方法模式的工厂方法是通过new运算符重新创建一个新的对象(相当于原型模式的深拷贝实现),而原型模式是通过调用MemberwiseClone方法来对原来对象进行拷贝,也就是复制,同时在原型模式优点中也介绍了与工厂方法的区别(第三点)。

本专题中所有源码:设计模式之原型模式

一、引言

在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类)、AccessoriesPhone(挂件手机类)等,这样就会导致 ”子类爆炸“问题,为了解决这个问题,我们可以使用装饰者模式来动态地给一个对象添加额外的职责。下面让我们看看装饰者模式。

二、装饰者模式的详细介绍

2.1 定义

装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能。

2.2 装饰者模式实现

这里以手机和手机配件的例子来演示装饰者模式的实现,具体代码如下:

复制代码

///


/// 手机抽象类,即装饰者模式中的抽象组件类 ///

public abstract class Phone
{ public abstract void Print();
} ///
/// 苹果手机,即装饰着模式中的具体组件类 ///

public class ApplePhone:Phone
{ ///
/// 重写基类方法 ///

public override void Print()
{
Console.WriteLine(“开始执行具体的对象——苹果手机”);
}
} ///
/// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Photo ///

public abstract class Decorator:Phone
{ private Phone phone; public Decorator(Phone p)
{ this.phone = p;
} public override void Print()
{ if (phone != null)
{
phone.Print();
}
}
} ///
/// 贴膜,即具体装饰者 ///

public class Sticker : Decorator
{ public Sticker(Phone p)
: base(p)
{
} public override void Print()
{ base.Print(); // 添加新的行为
AddSticker();
} ///
/// 新的行为方法 ///

public void AddSticker()
{
Console.WriteLine(“现在苹果手机有贴膜了”);
}
} ///
/// 手机挂件 ///

public class Accessories : Decorator
{ public Accessories(Phone p)
: base(p)
{
} public override void Print()
{ base.Print(); // 添加新的行为
AddAccessories();
} ///
/// 新的行为方法 ///

public void AddAccessories()
{
Console.WriteLine(“现在苹果手机有漂亮的挂件了”);
}
}

复制代码

此时客户端调用代码如下:

复制代码

class Customer
{ static void Main(string[] args)
{ // 我买了个苹果手机
Phone phone = new ApplePhone(); // 现在想贴膜了
Decorator applePhoneWithSticker = new Sticker(phone); // 扩展贴膜行为
applePhoneWithSticker.Print();
Console.WriteLine(“-———————\n”); // 现在我想有挂件了
Decorator applePhoneWithAccessories = new Accessories(phone); // 扩展手机挂件行为
applePhoneWithAccessories.Print();
Console.WriteLine(“-———————\n”); // 现在我同时有贴膜和手机挂件了
Sticker sticker = new Sticker(phone);
Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker);
applePhoneWithAccessoriesAndSticker.Print();
Console.ReadLine();
}

复制代码

从上面的客户端代码可以看出,客户端可以动态地将手机配件增加到手机上,如果需要添加手机外壳时,此时只需要添加一个继承Decorator的手机外壳类,从而,装饰者模式扩展性也非常好。

2.3 装饰者模式的类图

实现完了装饰者模式之后,让我们看看装饰者模式实现中类之间的关系,具体见下图:

在装饰者模式中各个角色有:

  • 抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
  • 具体构件(AppPhone)角色:定义一个将要接收附加责任的类。
  • 装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。

三、装饰者模式的优缺点

看完装饰者模式的详细介绍之后,我们继续分析下它的优缺点。

优点:

  1. 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
  2. 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
  3. 装饰者模式有很好地可扩展性

缺点:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

四、使用场景

下面让我们看看装饰者模式具体在哪些情况下使用,在以下情况下应当使用装饰者模式:

  1. 需要扩展一个类的功能或给一个类增加附加责任。
  2. 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能

五、.NET中装饰者模式的实现

在.NET 类库中也有装饰者模式的实现,该类就是System.IO.Stream,下面看看Stream类结构:

上图中,BufferedStream、CryptoStream和GZipStream其实就是两个具体装饰类,这里的装饰者模式省略了抽象装饰角色(Decorator)。下面演示下客户端如何动态地为MemoryStream动态增加功能的。

复制代码

MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99}); // 扩展缓冲的功能
BufferedStream buffStream = new BufferedStream(memoryStream); // 添加加密的功能
CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write); // 添加压缩功能
GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);

复制代码

六、总结

到这里,装饰者模式的介绍就结束了,装饰者模式采用对象组合而非继承的方式实现了再运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的 ”灵活性差“和”多子类衍生问题“。同时它很好地符合面向对象设计原则中 ”优先使用对象组合而非继承“和”开放-封闭“原则。

本专题所有源码:设计模式之装饰者模式

一、引言

     C#版本的23种设计模式已经写完了,现在也到了一个该总结的时候了。说起设计模式,我的话就比较多了。刚开始写代码的时候,有需求就写代码来解决需求,如果有新的需求,或者需求变了,我就想当然的修改自己的代码来满足新的需求,这样做感觉是理所当然的,也没感觉有什么不妥的地方。写了两年多代码,偶尔一次,听说了设计模式,据听说设计模式就是软件界的“独孤九剑”,学会之后就可以天下无敌,于是我就开始了我的进修之路。

       想当初,我就像很多的初学编程的人一样,在面试官面前很容易说出面向对象语言的三大特征:继承,多态和封装,其实,我根本不理解这三个词语的意思,或者说理解的很浅薄。当然也有很多概念是不清楚的,比如:OOPL(面向对象语言)是不是就是OO的全部,面向对象的设计模式和设计模式的到底有什么区别,等等相关问题。自从自己学了设计模式,很多概念变得清晰明了,做事有原则了,或者说有准则了,不像以前只是解决了问题就好,根本不管代码写的是否合理。写的代码可以很优美了,结构更合理了,自己开始重新思考代码这个东西。

     学习设计模式并不是一帆风顺的,尤其是刚开始的时候,由于自己很多概念不是很清楚,也走了很多弯路,但是通过自己的坚持,通过自己不断的看,不断的写,对模式的理解也越来越准确了。写代码不是一个很简单的事情,做任何事都是有原则的,写代码也一样,如果自己心中对做的事情没有准则,那就和无头的苍蝇一样,做与不做是一样的。写代码和写好代码是不一样的,如果要写好的代码,考虑的问题更多了,考虑稳定性,扩展性和耦合性,当然也要考虑上游和下游关联的问题,让你做事的时候知道怎么做,也知道为什么这么做,这就是学习设计模式带来的好处。

     好了,说了也不少了,我把我写的模式都罗列出来,每个模式都有链接,可以直接点击进入查看和阅读,希望对大家阅读有益。

系列导航:

创建型:

    C#设计模式(1)——单例模式(Singleton Pattern)

    C#设计模式(2)——工厂方法模式(Factory Pattern)

    C#设计模式(3)——抽象工厂模式(Abstract Pattern)

    C#设计模式(4)——建造模式(Builder Pattern)

    C#设计模式(5)——原型模式(Prototype Pattern)

结构型:

    C#设计模式(6)——适配器模式(Adapter Pattern)

    C#设计模式(7)——桥接模式(Bridge Pattern)

    C#设计模式(8)——装饰模式(Decorator Pattern)

    C#设计模式(9)——组合模式(Composite Pattern)

    C#设计模式(10)——外观模式(Facade Pattern)

    C#设计模式(11)——享元模式(Flyweight Pattern)

    C#设计模式(12)——代理模式(Proxy Pattern)

行为型:

    C#设计模式(13)——模板方法模式(Template Method)

    C#设计模式(14)——命令模式(Command Pattern)

    C#设计模式(15)——迭代器模式(Iterator Pattern)

    C#设计模式(16)——观察者模式(Observer Pattern)

    C#设计模式(17)——中介者模式(Mediator Pattern)

    C#设计模式(18)——状态模式(State Pattern)

    C#设计模式(19)——策略模式(Stragety Pattern)

    C#设计模式(20)——责任链模式(Chain of Responsibility Pattern)

    C#设计模式(21)——访问者模式(Vistor Pattern)

    C#设计模式(22)——备忘录模式(Memento Pattern)

    C#设计模式(23)——解释器模式(Interpreter Pattern)

二、 面向对象的设计原则

       写代码也是有原则的,我们之所以使用设计模式,主要是为了适应变化,提高代码复用率,使软件更具有可维护性和可扩展性。如果我们能更好的理解这些设计原则,对我们理解面向对象的设计模式也是有帮助的,因为这些模式的产生是基于这些原则的。这些规则是:单一职责原则(SRP)、开放封闭原则(OCP)、里氏代替原则(LSP)、依赖倒置原则(DIP)、接口隔离原则(ISP)、合成复用原则(CRP)和迪米特原则(LoD)。下面我们就分别介绍这几种设计原则。

   2.1、单一职责原则(SRP):

  (1)、SRP(Single Responsibilities Principle)的定义:就一个类而言,应该仅有一个引起它变化的原因。简而言之,就是功能要单一。

  (2)、如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其它职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。(敏捷软件开发)

  (3)、软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。

     小结:单一职责原则(SRP)可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。责任过多,引起它变化的原因就越多,这样就会导致职责依赖,大大损伤其内聚性和耦合度。

   2.2、开放关闭原则(OCP)

  (1)、OCP(Open-Close Principle)的定义:就是说软件实体(类,方法等等)应该可以扩展(扩展可以理解为增加),但是不能在原来的方法或者类上修改,也可以这样说,对增加代码开放,对修改代码关闭。

  (2)、OCP的两个特征: 对于扩展(增加)是开放的,因为它不影响原来的,这是新增加的。对于修改是封闭的,如果总是修改,逻辑会越来越复杂。

     小结:开放封闭原则(OCP)是面向对象设计的核心思想。遵循这个原则可以为我们面向对象的设计带来巨大的好处:可维护(维护成本小,做管理简单,影响最小)、可扩展(有新需求,增加就好)、可复用(不耦合,可以使用以前代码)、灵活性好(维护方便、简单)。开发人员应该仅对程序中出现频繁变化的那些部分做出抽象,但是不能过激,对应用程序中的每个部分都刻意地进行抽象同样也不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。

   2.3、里氏代替原则(LSP)

      (1)、LSP(Liskov Substitution Principle)的定义:子类型必须能够替换掉它们的父类型。更直白的说,LSP是实现面向接口编程的基础。

      小结:任何基类可以出现的地方,子类一定可以出现,所以我们可以实现面向接口编程。 LSP是继承复用的基石,只有当子类可以替换掉基类,软件的功能不受到影响时,基类才能真正被复用,而子类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

   2.4、依赖倒置原则(DIP)

     (1)、DIP(Dependence Inversion Principle)的定义:抽象不应该依赖细节,细节应该依赖于抽象。简单说就是,我们要针对接口编程,而不要针对实现编程。

     (2)、高层模块不应该依赖低层模块,两个都应该依赖抽象,因为抽象是稳定的。抽象不应该依赖具体(细节),具体(细节)应该依赖抽象。

      小结:依赖倒置原则其实可以说是面向对象设计的标志,如果在我们编码的时候考虑的是面向接口编程,而不是简单的功能实现,体现了抽象的稳定性,只有这样才符合面向对象的设计。

   2.5 接口隔离原则(ISP)

     (1)、接口隔离原则(Interface Segregation Principle, ISP)指的是使用多个专门的接口比使用单一的总接口要好。也就是说不要让一个单一的接口承担过多的职责,而应把每个职责分离到多个专门的接口中,进行接口分离。过于臃肿的接口是对接口的一种污染。

     (2)、使用多个专门的接口比使用单一的总接口要好。

     (3)、一个类对另外一个类的依赖性应当是建立在最小的接口上的。

     (4)、一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

     (5)、“不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

       小结:接口隔离原则(ISP)告诉我们,在做接口设计的时候,要尽量设计的接口功能单一,功能单一,使它变化的因素就少,这样就更稳定,其实这体现了高内聚,低耦合的原则,这样做也避免接口的污染。

   2.6 组合复用原则(CRP)

     (1)、组合复用原则(Composite Reuse Principle, CRP)就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分。新对象通过向这些对象的委派达到复用已用功能的目的。简单地说,就是要尽量使用合成/聚合,尽量不要使用继承。

     (2)、要使用好组合复用原则,首先需要区分”Has—A”和“Is—A”的关系。 “Is—A”是指一个类是另一个类的“一种”,是属于的关系,而“Has—A”则不同,它表示某一个角色具有某一项责任。导致错误的使用继承而不是聚合的常见的原因是错误地把“Has—A”当成“Is—A”.例如:鸡是动物,这就是“Is-A”的表现,某人有一个手枪,People类型里面包含一个Gun类型,这就是“Has-A”的表现。

     小结:组合/聚合复用原则可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其他类造成的影响相对较少,因此一般首选使用组合/聚合来实现复用;其次才考虑继承,在使用继承时,需要严格遵循里氏替换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

   2.7 迪米特法则(Law of Demeter)

      (1)、迪米特法则(Law of Demeter,LoD)又叫最少知识原则(Least Knowledge Principle,LKP),指的是一个对象应当对其他对象有尽可能少的了解。也就是说,一个模块或对象应尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立,这样当一个模块修改时,影响的模块就会越少,扩展起来更加容易。

      (2)、关于迪米特法则其他的一些表述有:只与你直接的朋友们通信;不要跟“陌生人”说话。

      (3)、外观模式(Facade Pattern)和中介者模式(Mediator Pattern)就使用了迪米特法则。

       小结:迪米特法则的初衷是降低类之间的耦合,实现类型之间的高内聚,低耦合,这样可以解耦。但是凡事都有度,过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

三、创建型模式

    创建型模式就是用来解决对象实例化和使用的客户端耦合的模式,可以让客户端和对象实例化都独立变化,做到相互不影响。创建型模式包括单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。

    3.1、单例模式(Singleton Pattern):解决的是实例化对象的个数的问题,该模式是把对象的数量控制为一个,该模式可以扩展,可以把实例对象扩展为N个对象,N>=2。比如对象池的实现。

       动机(Motivate):在软件系统构建的过程中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?如果指望使用者不使用构造器来重复创建对象,这是不对的。这应该是类设计者的责任,而不是使用者的责任。

       意图(Intent):保证一个类仅有一个实例,并提供一个该实例的全局访问点。

       具体结构图如下所示
      

       示例代码:

复制代码

1 ///


2 /// 单例模式的实现 3 ///

4 public sealed class Singleton 5 {
6 // 定义一个静态变量来保存类的实例
7 private static volatile Singleton uniqueInstance; 8
9 // 定义一个标识确保线程同步
10 private static readonly object locker = new object(); 11
12 // 定义私有构造函数,使外界不能创建该类实例
13 private Singleton() 14 { 15 } 16
17 ///
18 /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 19 ///

20 ///
21 public static Singleton GetInstance() 22 { 23 // 当第一个线程运行到这里时,此时会对locker对象 “加锁”, 24 // 当第二个线程运行该方法时,首先检测到locker对象为”加锁”状态,该线程就会挂起等待第一个线程解锁 25 // lock语句运行完之后(即线程运行完之后)会对该对象”解锁” 26 // 双重锁定只需要一句判断就可以了
27 if (uniqueInstance == null) 28 { 29 lock (locker) 30 { 31 // 如果类的实例不存在则创建,否则直接返回
32 if (uniqueInstance == null) 33 { 34 uniqueInstance = new Singleton(); 35 } 36 } 37 } 38 return uniqueInstance; 39 } 40 }

复制代码

   

3.2、工厂方法模式(Factory Method Pattern):一种工厂生产一种产品,工厂类和产品类是一一对应的,他们是平行的等级结构,强调的是“单个对象”的变化。

       动机(Motivate):在软件系统的构建过程中,经常面临着“某个对象”的创建工作:由于需求的变化,这个对象(的具体实现)经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖对象的对象”不随着需求改变而改变?

       意图(Intent):定义一个创建对象的工厂接口,由其子类决定要实例化的类,将实际创建工作推迟到子类中。

       具体结构图如下所示:

    3.3、抽象工厂模式(Abstract Factory Pattern):该模式关注的是多批多系列相互依赖的产品的变化,比如:SQLConnection,SQLCommand,SqlDataReader,SqlDataAdapter,就是一批相互依赖的对象,他们变化可以产生OledbConnection,OledbCommand,OledbDataReader,OledbDataAdapter

       动机(Motivate):在软件系统中,经常面临着”一系统相互依赖的对象”的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种”封装机制”来避免客户程序和这种”多系列具体对象创建工作”的紧耦合?

       意图(Intent):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

       具体结构图如下所示

           

       代码实例

复制代码

1 ///


2 /// 下面以不同系列房屋的建造为例子演示抽象工厂模式 3 /// 因为每个人的喜好不一样,我喜欢欧式的,我弟弟就喜欢现代的 4 /// 客户端调用 5 ///

6 class Client 7 {
8 static void Main(string[] args)
9 {
10 // 哥哥的欧式风格的房子
11 AbstractFactory europeanFactory= new EuropeanFactory(); 12 europeanFactory.CreateRoof().Create();
13 europeanFactory.CreateFloor().Create();
14 europeanFactory.CreateWindow().Create();
15 europeanFactory.CreateDoor().Create();
16
17
18 //弟弟的现代风格的房子
19 AbstractFactory modernizationFactory = new 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 public abstract class AbstractFactory 32 {
33 // 抽象工厂提供创建一系列产品的接口,这里作为例子,只给出了房顶、地板、窗户和房门创建接口
34 public abstract Roof CreateRoof(); 35 public abstract Floor CreateFloor(); 36 public abstract Window CreateWindow(); 37 public abstract Door CreateDoor(); 38 }
39
40 ///
41 /// 欧式风格房子的工厂,负责创建欧式风格的房子 42 ///

43 public class EuropeanFactory : AbstractFactory 44 {
45 // 制作欧式房顶
46 public override Roof CreateRoof() 47 {
48 return new EuropeanRoof(); 49 }
50
51 // 制作欧式地板
52 public override Floor CreateFloor() 53 {
54 return new EuropeanFloor(); 55 }
56
57 // 制作欧式窗户
58 public override Window CreateWindow() 59 {
60 return new EuropeanWindow(); 61 }
62
63 // 制作欧式房门
64 public override Door CreateDoor() 65 {
66 return new EuropeanDoor(); 67 }
68 }
69
70 ///
71 /// 现在风格房子的工厂,负责创建现代风格的房子 72 ///

73 public class ModernizationFactory : AbstractFactory 74 {
75 // 制作现代房顶
76 public override Roof CreateRoof() 77 {
78 return new ModernizationRoof(); 79 }
80
81 // 制作现代地板
82 public override Floor CreateFloor() 83 {
84 return new ModernizationFloor(); 85 }
86
87 // 制作现代窗户
88 public override Window CreateWindow() 89 {
90 return new ModernizationWindow(); 91 }
92
93 // 制作现代房门
94 public override Door CreateDoor() 95 {
96 return new ModernizationDoor(); 97 }
98 }
99
100 ///
101 /// 房顶抽象类,子类的房顶必须继承该类 102 ///

103 public abstract class Roof 104 { 105 ///
106 /// 创建房顶 107 ///

108 public abstract void Create(); 109 } 110
111 ///
112 /// 地板抽象类,子类的地板必须继承该类 113 ///

114 public abstract class Floor 115 { 116 ///
117 /// 创建地板 118 ///

119 public abstract void Create(); 120 } 121
122 ///
123 /// 窗户抽象类,子类的窗户必须继承该类 124 ///

125 public abstract class Window 126 { 127 ///
128 /// 创建窗户 129 ///

130 public abstract void Create(); 131 } 132
133 ///
134 /// 房门抽象类,子类的房门必须继承该类 135 ///

136 public abstract class Door 137 { 138 ///
139 /// 创建房门 140 ///

141 public abstract void Create(); 142 } 143
144 ///
145 /// 欧式地板类 146 ///

147 public class EuropeanFloor : Floor 148 { 149 public override void Create() 150 { 151 Console.WriteLine(“创建欧式的地板”); 152 } 153 } 154
155
156 ///
157 /// 欧式的房顶 158 ///

159 public class EuropeanRoof : Roof 160 { 161 public override void Create() 162 { 163 Console.WriteLine(“创建欧式的房顶”); 164 } 165 } 166
167
168 ///
169 ///欧式的窗户 170 ///

171 public class EuropeanWindow : Window 172 { 173 public override void Create() 174 { 175 Console.WriteLine(“创建欧式的窗户”); 176 } 177 } 178
179
180 ///
181 /// 欧式的房门 182 ///

183 public class EuropeanDoor : Door 184 { 185 public override void Create() 186 { 187 Console.WriteLine(“创建欧式的房门”); 188 } 189 } 190
191 ///
192 /// 现代的房顶 193 ///

194 public class ModernizationRoof : Roof 195 { 196 public override void Create() 197 { 198 Console.WriteLine(“创建现代的房顶”); 199 } 200 } 201
202 ///
203 /// 现代的地板 204 ///

205 public class ModernizationFloor : Floor 206 { 207 public override void Create() 208 { 209 Console.WriteLine(“创建现代的地板”); 210 } 211 } 212
213 ///
214 /// 现代的窗户 215 ///

216 public class ModernizationWindow : Window 217 { 218 public override void Create() 219 { 220 Console.WriteLine(“创建现代的窗户”); 221 } 222 } 223
224 ///
225 /// 现代的房门 226 ///

227 public class ModernizationDoor : Door 228 { 229 public override void Create() 230 { 231 Console.WriteLine(“创建现代的房门”); 232 } 233 }

复制代码

   

3.4、建造者模式(Builder Pattern):该模式要解决的是由多个子部分对象构成的一个复杂对象的创建的问题,该复杂对象构成算法稳定,各个子部分对象易变化的情况。强调组装过程的稳定。

       动机(Motivate):在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?

       意图(Intent):将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

                                  将一个产品的表示形式与产品的组装过程分割开来,从而可以使同一个组装过程(这个构建过程是稳定的,也就是算法)生成具体不同的表现的产品对象。

       具体结构图如下所示

                

    3.5、原型模式(Prototype Pattern):通过制定实例类型来复制对象

       动机(Motivate):在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?

       意图(Intent):使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

       具体结构图如下所示:

四、结构型模式

    结构型模式主要研究的是类和对象的组合的问题。它包括两种类型,一是类结构型模式:指的是采用继承机制来组合实现功能;二是对象结构型模式:指的是通过组合对象的方式来实现新的功能。该系列模式包括:适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式和代理模式。

    4.1、适配器模式(Adapter Pattern):该模式主要关注的是接口转换的问题,将匹配的接口通过适配对接工作。

       动机(Motivate):在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?

       意图(Intent):将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

                                  适配器模式意在转换接口,它能够使原本不能再一起工作的两个类一起工作,所以经常用来在类库的复用、代码迁移等方面。 适配器模式包括类适配器模式和对象适配器模式,

       具体结构图如下所示:

       类适配器模式:

       对象适配器模式:

    4.2、桥接模式(Bridge Pattern):该模式注重分离接口与其实现,接口是针对客户的,接口的内在实现是通过“实现层次”来完成的,支持多维度变化。

       动机(Motivate):在很多游戏场景中,会有这样的情况:【装备】本身会有的自己固有的逻辑,比如枪支,会有型号的问题,同时现在很多的游戏又在不同的介质平台上运行和使用,这样就使得游戏的【装备】具有了两个变化的维度——一个变化的维度为“平台的变化”,另一个变化的维度为“型号的变化”。如果我们要写代码实现这款游戏,难道我们针对每种平台都实现一套独立的【装备】吗?复用在哪里?如何应对这种“多维度的变化”?如何利用面向对象技术来使得【装备】可以轻松地沿着“平台”和“型号”两个方向变化,而不引入额外的复杂度?

       意图(Intent):将抽象部分与实现部分分离,使它们都可以独立地变化。

                       比如:就拿游戏装备来说,“手枪”,抽象部分是指手枪的型号,这个型号可以是G50,G55,针对不同平台,这些型号有不同的实现,针对这些不同平台的不同型号的实现,重新抽象,抽象的结构就是“实现的层次”,其实,到此,就形成了两个抽象层次,第一个层次,是枪支的型号的层次,另一个层次就是针对其实现的一个层次,这样就做到了抽象和实现的分离。

       具体结构图如下所示

          

       示例代码:

复制代码

1 namespace 桥接模式的实现 2 {
3 ///


4 /// 该抽象类就是抽象接口的定义,该类型就相当于是Abstraction类型 5 ///

6 public abstract class Database 7 {
8 //通过组合方式引用平台接口,此处就是桥梁,该类型相当于Implementor类型
9 protected PlatformImplementor _implementor; 10
11 //通过构造器注入,初始化平台实现
12 protected Database(PlatformImplementor implementor) 13 { 14 this._implementor = implementor; 15 } 16
17 //创建数据库–该操作相当于Abstraction类型的Operation方法
18 public abstract void Create(); 19 } 20
21 ///
22 /// 该抽象类就是实现接口的定义,该类型就相当于是Implementor类型 23 ///

24 public abstract class PlatformImplementor 25 { 26 //该方法就相当于Implementor类型的OperationImpl方法
27 public abstract void Process(); 28 } 29
30 ///
31 /// SqlServer2000版本的数据库,相当于RefinedAbstraction类型 32 ///

33 public class SqlServer2000 : Database 34 { 35 //构造函数初始化
36 public SqlServer2000(PlatformImplementor implementor) : base(implementor) { } 37
38 public override void Create() 39 { 40 this._implementor.Process(); 41 } 42 } 43
44 ///
45 /// SqlServer2005版本的数据库,相当于RefinedAbstraction类型 46 ///

47 public class SqlServer2005 : Database 48 { 49 //构造函数初始化
50 public SqlServer2005(PlatformImplementor implementor) : base(implementor) { } 51
52 public override void Create() 53 { 54 this._implementor.Process(); 55 } 56 } 57
58 ///
59 /// SqlServer2000版本的数据库针对Unix操作系统具体的实现,相当于ConcreteImplementorA类型 60 ///

61 public class SqlServer2000UnixImplementor : PlatformImplementor 62 { 63 public override void Process() 64 { 65 Console.WriteLine(“SqlServer2000针对Unix的具体实现”); 66 } 67 } 68
69 ///
70 /// SqlServer2005版本的数据库针对Unix操作系统的具体实现,相当于ConcreteImplementorB类型 71 ///

72 public sealed class SqlServer2005UnixImplementor : PlatformImplementor 73 { 74 public override void Process() 75 { 76 Console.WriteLine(“SqlServer2005针对Unix的具体实现”); 77 } 78 } 79
80 public class Program 81 { 82 static void Main() 83 { 84 PlatformImplementor SqlServer2000UnixImp = new SqlServer2000UnixImplementor(); 85 //还可以针对不同平台进行扩展,也就是子类化,这个是独立变化的
86
87 Database SqlServer2000Unix = new SqlServer2000(SqlServer2000UnixImp); 88 //数据库版本也可以进行扩展和升级,也进行独立的变化。 89
90 //以上就是两个维度的变化。 91
92 //就可以针对Unix执行操作了
93 SqlServer2000Unix.Create(); 94 } 95 } 96 }

复制代码

   

4.3、装饰模式(Decorator Pattern):该模式注重稳定接口,让接口不变,在此前提下为对象动态(关键点)的扩展功能。如果通过继承,各个功能点的组合就会形成过多的子类,维护起来就是麻烦。

       动机(Motivate):在房子装修的过程中,各种功能可以相互组合,来增加房子的功用。类似的,如果我们在软件系统中,要给某个类型或者对象增加功能,如果使用“继承”的方案来写代码,就会出现子类暴涨的情况。比如:IMarbleStyle是大理石风格的一个功能,IKeepWarm是保温的一个接口定义,IHouseSecurity是房子安全的一个接口,就三个接口来说,House是我们房子,我们的房子要什么功能就实现什么接口,如果房子要的是复合功能,接口不同的组合就有不同的结果,这样就导致我们子类膨胀严重,如果需要在增加功能,子类会成指数增长。这个问题的根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质(所谓静态特质,就是说如果想要某种功能,我们必须在编译的时候就要定义这个类,这也是强类型语言的特点。静态,就是指在编译的时候要确定的东西;动态,是指运行时确定的东西),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。如何使“对象功能的扩展”能够根据需要来动态(即运行时)地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?

       意图(Intent):动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。

       具体结构图如下所示

              

       示例代码:

复制代码

1 namespace 装饰模式的实现 2 {
3 ///


4 /// 该抽象类就是房子抽象接口的定义,该类型就相当于是Component类型,是饺子馅,需要装饰的,需要包装的 5 ///

6 public abstract class House 7 {
8 //房子的装修方法–该操作相当于Component类型的Operation方法
9 public abstract void Renovation(); 10 } 11
12 ///
13 /// 该抽象类就是装饰接口的定义,该类型就相当于是Decorator类型,如果需要具体的功能,可以子类化该类型 14 ///

15 public abstract class DecorationStrategy:House //关键点之二,体现关系为Is-a,有这这个关系,装饰的类也可以继续装饰了
16 { 17 //通过组合方式引用Decorator类型,该类型实施具体功能的增加 18 //这是关键点之一,包含关系,体现为Has-a
19 protected House _house; 20
21 //通过构造器注入,初始化平台实现
22 protected DecorationStrategy(House house) 23 { 24 this._house=house; 25 } 26
27 //该方法就相当于Decorator类型的Operation方法
28 public override void Renovation() 29 { 30 if(this._house!=null) 31 { 32 this._house.Renovation(); 33 } 34 } 35 } 36
37 ///
38 /// PatrickLiu的房子,我要按我的要求做房子,相当于ConcreteComponent类型,这就是我们具体的饺子馅,我个人比较喜欢韭菜馅 39 ///

40 public sealed class PatrickLiuHouse:House 41 { 42 public override void Renovation() 43 { 44 Console.WriteLine(“装修PatrickLiu的房子”); 45 } 46 } 47
48
49 ///
50 /// 具有安全功能的设备,可以提供监视和报警功能,相当于ConcreteDecoratorA类型 51 ///

52 public sealed class HouseSecurityDecorator:DecorationStrategy 53 { 54 public HouseSecurityDecorator(House house):base(house){} 55
56 public override void Renovation() 57 { 58 base.Renovation(); 59 Console.WriteLine(“增加安全系统”); 60 } 61 } 62
63 ///
64 /// 具有保温接口的材料,提供保温功能,相当于ConcreteDecoratorB类型 65 ///

66 public sealed class KeepWarmDecorator:DecorationStrategy 67 { 68 public KeepWarmDecorator(House house):base(house){} 69
70 public override void Renovation() 71 { 72 base.Renovation(); 73 Console.WriteLine(“增加保温的功能”); 74 } 75 } 76
77 public class Program 78 { 79 static void Main() 80 { 81 //这就是我们的饺子馅,需要装饰的房子
82 House myselfHouse=new PatrickLiuHouse(); 83
84 DecorationStrategy securityHouse=new HouseSecurityDecorator(myselfHouse); 85 securityHouse.Renovation(); 86 //房子就有了安全系统了 87
88 //如果我既要安全系统又要保暖呢,继续装饰就行
89 DecorationStrategy securityAndWarmHouse=new HouseSecurityDecorator(securityHouse); 90 securityAndWarmHouse.Renovation(); 91 } 92 } 93 }

复制代码

复制代码

1 namespace 命令模式的实现 2 {
3 ///


4 /// 俗话说:“好吃不如饺子,舒服不如倒着”。今天奶奶发话要吃他大孙子和孙媳妇包的饺子。今天还拿吃饺子这件事来说说命令模式的实现吧。 5 ///

6 class Client 7 {
8 static void Main(string[] args)
9 { 10 //奶奶想吃猪肉大葱馅的饺子
11 PatrickLiuAndWife liuAndLai = new PatrickLiuAndWife();//命令接受者
12 Command command = new MakeDumplingsCommand(liuAndLai);//命令
13 PaPaInvoker papa = new PaPaInvoker(command); //命令请求者 14
15 //奶奶发布命令
16 papa.ExecuteCommand(); 17
18
19 Console.Read(); 20 } 21 } 22
23 //这个类型就是请求者角色–也就是我爸爸的角色,告诉奶奶要吃饺子
24 public sealed class PaPaInvoker 25 { 26 //我爸爸从奶奶那里接受到的命令
27 private Command _command; 28
29 //爸爸开始接受具体的命令
30 public PaPaInvoker(Command command) 31 { 32 this._command = command; 33 } 34
35 //爸爸给我们下达命令
36 public void ExecuteCommand() 37 { 38 _command.MakeDumplings(); 39 } 40 } 41
42 //该类型就是抽象命令角色–Commmand,定义了命令的抽象接口,任务是包饺子
43 public abstract class Command 44 { 45 //真正任务的接受者
46 protected PatrickLiuAndWife _worker; 47
48 protected Command(PatrickLiuAndWife worker) 49 { 50 _worker = worker; 51 } 52
53 //该方法就是抽象命令对象Command的Execute方法
54 public abstract void MakeDumplings(); 55 } 56
57 //该类型是具体命令角色–ConcreteCommand,这个命令完成制作“猪肉大葱馅”的饺子
58 public sealed class MakeDumplingsCommand : Command 59 { 60 public MakeDumplingsCommand(PatrickLiuAndWife worker) : base(worker) { } 61
62 //执行命令–包饺子
63 public override void MakeDumplings() 64 { 65 //执行命令—包饺子
66 _worker.Execute(“今天包的是农家猪肉和农家大葱馅的饺子”); 67 } 68 } 69
70 //该类型是具体命令接受角色Receiver,具体包饺子的行为是我们夫妻俩来完成的
71 public sealed class PatrickLiuAndWife 72 { 73 //这个方法相当于Receiver类型的Action方法
74 public void Execute(string job) 75 { 76 Console.WriteLine(job); 77 } 78 } 79 }

复制代码

   

4.4、组合模式(Composite Pattern):该模式着重解决统一接口的问题,将“一对多”的关系转化为“一对一”的关系,让使用叶子节点和树干节点保持接口一致。

       动机(Motivate):客户代码过多地依赖于对象容器(对象容器是对象的容器,细细评味)复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等方面的弊端。如何将“客户代码与复杂的对象容器内部结构”解耦?如何让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?

       意图(Intent):将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

       具体结构图如下所示:

    4.5、外观模式(Facade Pattern):该模式注重简化接口,简化组件系统与外部客户程序的依赖关系,是Lod(迪米特原则,也叫:最少知识原则)原则的最好的体现,

       动机(Motivate):在软件系统开发的过程中,当组件的客户(即外部接口,或客户程序)和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?

       意图(Intent):为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

       具体结构图如下所示:

    4.6、享元模式(Flyweight Pattern):该模式注重保留接口,在内部使用共享技术对对象存储进行优化

       动机(Motivate):在软件系统中,采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价——主要指内存需求方面的代价。如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?

       意图(Intent):运用共享技术有效地支持大量细粒度的对象。

                                 在.NET类库中,String类的实现就使用了享元模式,String类采用字符串驻留池的来使字符串进行共享。

       具体结构图如下所示

           

    4.7、代理模式(Proxy Pattern):该模式注重假借代理接口,控制对真实对象的访问,通过增加间接层来实现灵活控制,比如可以在访问正真对象之前进行权限验证,生活中的明星的代理就是很好的例子,要想接触明星,先要和他的经纪人打交道。

       动机(Motivate):在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者、或者系统结构带来很多麻烦。如何在不失去透明操作对象的同时来管理/控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。

       意图(Intent):为其他对象提供一种代理以控制对这个对象的访问。

       具体结构图如下所示:

             

五、行为型模式

    行为型模式主要讨论的是在不同对象之间划分责任和算法的抽象化的问题。行为型模式又分为类的行为模式和对象的行为模式两种。

    类的行为模式——使用继承关系在几个类之间分配行为。

对象的行为模式——使用对象聚合的方式来分配行为。

    行为型模式包括11种模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、状态模式、策略模式、责任链模式、访问者模式、解释器模式和备忘录模式。

    5.1、模板方法模式(Template Method Pattern):该模式注重对算法结构的封装,定义算法骨架,并且稳定,但是支持算法子步骤的变化。

       动机(Motivate):在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

       意图(Intent):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

       具体结构图如下所示

             

    5.2、命令模式(Command Pattern):该模式注重将请求封装为对象,通过将一组行为抽象为对象,实现行为请求者和行为实现者之间的解耦。也可以实现“撤销/重做”的功能,类似“宏”的功能实现也很容易。

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

       意图(Intent):将一个请求封装为一个对象,从而使你可用不同的请求对客户(客户程序,也是行为的请求者)进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。命令模式的实现可以提供命令的撤销和恢复功能。

       具体结构图如下所示

            

       代码实例

复制代码

1 namespace 命令模式的实现 2 {
3 ///


4 /// 俗话说:“好吃不如饺子,舒服不如倒着”。今天奶奶发话要吃他大孙子和孙媳妇包的饺子。今天还拿吃饺子这件事来说说命令模式的实现吧。 5 ///

6 class Client 7 {
8 static void Main(string[] args)
9 { 10 //奶奶想吃猪肉大葱馅的饺子
11 PatrickLiuAndWife liuAndLai = new PatrickLiuAndWife();//命令接受者
12 Command command = new MakeDumplingsCommand(liuAndLai);//命令
13 PaPaInvoker papa = new PaPaInvoker(command); //命令请求者 14
15 //奶奶发布命令
16 papa.ExecuteCommand(); 17
18
19 Console.Read(); 20 } 21 } 22
23 //这个类型就是请求者角色–也就是我爸爸的角色,告诉奶奶要吃饺子
24 public sealed class PaPaInvoker 25 { 26 //我爸爸从奶奶那里接受到的命令
27 private Command _command; 28
29 //爸爸开始接受具体的命令
30 public PaPaInvoker(Command command) 31 { 32 this._command = command; 33 } 34
35 //爸爸给我们下达命令
36 public void ExecuteCommand() 37 { 38 _command.MakeDumplings(); 39 } 40 } 41
42 //该类型就是抽象命令角色–Commmand,定义了命令的抽象接口,任务是包饺子
43 public abstract class Command 44 { 45 //真正任务的接受者
46 protected PatrickLiuAndWife _worker; 47
48 protected Command(PatrickLiuAndWife worker) 49 { 50 _worker = worker; 51 } 52
53 //该方法就是抽象命令对象Command的Execute方法
54 public abstract void MakeDumplings(); 55 } 56
57 //该类型是具体命令角色–ConcreteCommand,这个命令完成制作“猪肉大葱馅”的饺子
58 public sealed class MakeDumplingsCommand : Command 59 { 60 public MakeDumplingsCommand(PatrickLiuAndWife worker) : base(worker) { } 61
62 //执行命令–包饺子
63 public override void MakeDumplings() 64 { 65 //执行命令—包饺子
66 _worker.Execute(“今天包的是农家猪肉和农家大葱馅的饺子”); 67 } 68 } 69
70 //该类型是具体命令接受角色Receiver,具体包饺子的行为是我们夫妻俩来完成的
71 public sealed class PatrickLiuAndWife 72 { 73 //这个方法相当于Receiver类型的Action方法
74 public void Execute(string job) 75 { 76 Console.WriteLine(job); 77 } 78 } 79 }

复制代码

   

5.3、迭代器模式(Iterator Pattern):该模式注重封装对集合的操作,支持集合实例的变化,屏蔽集合对象内部复杂结构,提供客户程序对它的透明遍历。

       动机(Motivate):在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。

       意图(Intent): 提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

       具体结构图如下所示

            

    5.4、观察者模式(Observer Pattern):该模式注重的是变化通知,变化通知指目标对象发生变化,依赖的对象就能获得通知并进行相应操作,这是一种“一对多”的关系。

       动机(Motivate):在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。

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

       具体结构图如下所示

              

    5.5、中介者模式(Mediator Pattern):该模式注重封装对象间的交互,通过封装一系列对象之间的复杂交互,使他们不需要显式相互引用,实现解耦。

       动机(Motivate):在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断地变化。在这种情况下,我们可使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好地抵御变化。

       意图(Intent):定义了一个中介对象来封装一系列对象之间的交互关系。中介者使各个对象之间不需要显式地相互引用,从而使耦合性降低,而且可以独立地改变它们之间的交互行为。

       具体的结构图如下所示

           

       代码实例

复制代码

1 namespace 中介者模式的实现 2 {
3 //抽象中介者角色
4 public interface Mediator 5 {
6 void Command(Department department); 7 }
8
9 //总经理–相当于具体中介者角色
10 public sealed class President : Mediator 11 {
12 //总经理有各个部门的管理权限
13 private Financial _financial; 14 private Market _market; 15 private Development _development; 16
17 public void SetFinancial(Financial financial) 18 {
19 this._financial = financial; 20 }
21 public void SetDevelopment(Development development) 22 {
23 this._development = development; 24 }
25 public void SetMarket(Market market) 26 {
27 this._market = market; 28 }
29
30 public void Command(Department department) 31 {
32 if (department.GetType() == typeof(Market))
33 {
34 _financial.Process();
35 }
36 }
37 }
38
39 //同事类的接口
40 public abstract class Department 41 {
42 //持有中介者(总经理)的引用
43 private Mediator mediator; 44
45 protected Department(Mediator mediator) 46 {
47 this.mediator = mediator; 48 }
49
50 public Mediator GetMediator 51 {
52 get { return mediator; } 53 private set { this.mediator = value; } 54 }
55
56 //做本部门的事情
57 public abstract void Process(); 58
59 //向总经理发出申请
60 public abstract void Apply(); 61 }
62
63 //开发部门
64 public sealed class Development : Department 65 {
66 public Development(Mediator m) : base(m) { }
67
68 public override void Process() 69 {
70 Console.WriteLine(“我们是开发部门,要进行项目开发,没钱了,需要资金支持!”);
71 }
72
73 public override void Apply() 74 {
75 Console.WriteLine(“专心科研,开发项目!”);
76 }
77 }
78
79 //财务部门
80 public sealed class Financial : Department 81 {
82 public Financial(Mediator m) : base(m) { }
83
84 public override void Process() 85 {
86 Console.WriteLine(“汇报工作!没钱了,钱太多了!怎么花?”);
87 }
88
89 public override void Apply() 90 {
91 Console.WriteLine(“数钱!”);
92 }
93 }
94
95 //市场部门
96 public sealed class Market : Department 97 {
98 public Market(Mediator mediator) : base(mediator) { }
99
100 public override void Process() 101 { 102 Console.WriteLine(“汇报工作!项目承接的进度,需要资金支持!”); 103 GetMediator.Command(this); 104 } 105
106 public override void Apply() 107 { 108 Console.WriteLine(“跑去接项目!”); 109 } 110 } 111
112
113 class Program 114 { 115 static void Main(String[] args) 116 { 117 President mediator = new President(); 118 Market market = new Market(mediator); 119 Development development = new Development(mediator); 120 Financial financial = new Financial(mediator); 121
122 mediator.SetFinancial(financial); 123 mediator.SetDevelopment(development); 124 mediator.SetMarket(market); 125
126 market.Process(); 127 market.Apply(); 128
129 Console.Read(); 130 } 131 } 132 }

复制代码

   

5.6、状态模式(State Pattern):该模式注重封装与状态相关的行为(定义状态类,会把和一个状态相关的操作都放到这个类里面),支持状态的变化,从而在其内部状态改变时改变它的行为。

       动机(Motivate):在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?

       意图(Intent):允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。

       具体结构图如下所示

              

       代码实例

复制代码

1 namespace 状态模式的实现 2 {
3 //环境角色—相当于Context类型
4 public sealed class Order 5 {
6 private State current; 7
8 public Order() 9 {
10 //工作状态初始化为上午工作状态
11 current = new WaitForAcceptance(); 12 IsCancel = false;
13 }
14 private double minute; 15 public double Minute 16 {
17 get { return minute; } 18 set { minute = value; } 19 }
20
21 public bool IsCancel { get; set; }
22
23 private bool finish; 24 public bool TaskFinished 25 {
26 get { return finish; } 27 set { finish = value; } 28 }
29 public void SetState(State s) 30 {
31 current = s; 32 }
33 public void Action() 34 {
35 current.Process(this);
36 }
37 }
38
39 //抽象状态角色—相当于State类型
40 public interface State 41 {
42 //处理订单
43 void Process(Order order); 44 }
45
46 //等待受理–相当于具体状态角色
47 public sealed class WaitForAcceptance : State 48 {
49 public void Process(Order order) 50 {
51 System.Console.WriteLine(“我们开始受理,准备备货!”);
52 if (order.Minute < 30 && order.IsCancel) 53 {
54 System.Console.WriteLine(“接受半个小时之内,可以取消订单!”);
55 order.SetState(new CancelOrder()); 56 order.TaskFinished = true;
57 order.Action();
58 }
59 order.SetState(new AcceptAndDeliver()); 60 order.TaskFinished = false;
61 order.Action();
62 }
63 }
64
65 //受理发货—相当于具体状态角色
66 public sealed class AcceptAndDeliver : State 67 {
68 public void Process(Order order) 69 {
70 System.Console.WriteLine(“我们货物已经准备好,可以发货了,不可以撤销订单!”);
71 if (order.Minute < 30 && order.IsCancel) 72 {
73 System.Console.WriteLine(“接受半个小时之内,可以取消订单!”);
74 order.SetState(new CancelOrder()); 75 order.TaskFinished = true;
76 order.Action();
77 }
78 if (order.TaskFinished==false)
79 {
80 order.SetState(new Success()); 81 order.Action();
82 }
83 }
84 }
85
86 //交易成功—相当于具体状态角色
87 public sealed class Success : State 88 {
89 public void Process(Order order) 90 {
91 System.Console.WriteLine(“订单结算”);
92 order.SetState(new ConfirmationReceipt()); 93 order.TaskFinished = true;
94 order.Action();
95 }
96 }
97
98 //确认收货—相当于具体状态角色
99 public sealed class ConfirmationReceipt : State 100 { 101 public void Process(Order order) 102 { 103 System.Console.WriteLine(“检查货物,没问题可以就可以签收!”); 104 order.SetState(new ConfirmationReceipt()); 105 order.TaskFinished = true; 106 order.Action(); 107 } 108 } 109
110 //取消订单—相当于具体状态角色
111 public sealed class CancelOrder : State 112 { 113 public void Process(Order order) 114 { 115 System.Console.WriteLine(“检查货物,有问题,取消订单!”); 116 order.SetState(new CancelOrder()); 117 order.TaskFinished = true; 118 order.Action(); 119 } 120 } 121
122
123 public class Client 124 { 125 public static void Main(String[] args) 126 { 127 //订单
128 Order order = new Order(); 129 order.Minute = 9; 130 order.Action(); 131 //可以取消订单
132 order.IsCancel = true; 133 order.Minute = 20; 134 order.Action(); 135 order.Minute = 33; 136 order.Action(); 137 order.Minute = 43; 138 order.Action(); 139
140 Console.Read(); 141 } 142 } 143 }

复制代码

   

5.7、策略模式(Stragety Pattern):该模式注重封装算法,这里面没有算法骨架,一种算法就是一种解决方案,一种方法策略。支持算法的变化,通过封装一系列算法,可以做到算法的替换来满足客户的需求。

       动机(Motivate): 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

       意图(Intent):定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。

       具体结构图如下所示

          

    5.8、责任链模式(Chain of Responsibility Pattern):该模式注重封装对象责任,支持责任的变化,通过动态构建职责链,实现业务处理。在现实生活中,请假流程,采购流程等都是职责链模式很好的例子。

       动机(Motivate):在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合。如何使请求的发送者不需要指定具体的接受者,让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。

       意图(Intent):避免请求发送者与接收者耦合在一起,让多个对象都有可能接受请求,将这些对象连接成一条链,并且沿着这条链传递请求,知道有对象处理它为止。

       具体结构图如下所示

            

    5.9、访问者模式(Visitor Pattern):该模式注重封装对象操作变化,支持在运行时为类结构添加新的操作,在类层次结构中,在不改变各类的前提下定义作用于这些类实例的新的操作。

       动机(Motivate):在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?

       意图(Intent):表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。

       具体结构图如下所示

            

       代码实例

复制代码

1 namespace Vistor 2 {
3 //抽象图形定义—相当于“抽象节点角色”Element
4 public abstract class Shape 5 {
6 //画图形
7 public abstract void Draw(); 8 //外界注入具体访问者
9 public abstract void Accept(ShapeVisitor visitor); 10 }
11
12 //抽象访问者 Visitor
13 public abstract class ShapeVisitor 14 {
15 public abstract void Visit(Rectangle shape); 16
17 public abstract void Visit(Circle shape); 18
19 public abstract void Visit(Line shape); 20
21 //这里有一点要说:Visit方法的参数可以写成Shape吗?就是这样 Visit(Shape shape),当然可以,但是ShapeVisitor子类Visit方法就需要判断当前的Shape是什么类型,是Rectangle类型,是Circle类型,或者是Line类型。
22 }
23
24 //具体访问者 ConcreteVisitor
25 public sealed class CustomVisitor : ShapeVisitor 26 {
27 //针对Rectangle对象
28 public override void Visit(Rectangle shape) 29 {
30 Console.WriteLine(“针对Rectangle新的操作!”);
31 }
32 //针对Circle对象
33 public override void Visit(Circle shape) 34 {
35 Console.WriteLine(“针对Circle新的操作!”);
36 }
37 //针对Line对象
38 public override void Visit(Line shape) 39 {
40 Console.WriteLine(“针对Line新的操作!”);
41 }
42 }
43
44 //矩形—-相当于“具体节点角色” ConcreteElement
45 public sealed class Rectangle : Shape 46 {
47 public override void Draw() 48 {
49 Console.WriteLine(“矩形我已经画好!”);
50 }
51
52 public override void Accept(ShapeVisitor visitor) 53 {
54 visitor.Visit(this);
55 }
56 }
57
58 //圆形—相当于“具体节点角色”ConcreteElement
59 public sealed class Circle : Shape 60 {
61 public override void Draw() 62 {
63 Console.WriteLine(“圆形我已经画好!”);
64 }
65
66 public override void Accept(ShapeVisitor visitor) 67 {
68 visitor.Visit(this);
69 }
70 }
71
72 //直线—相当于“具体节点角色” ConcreteElement
73 public sealed class Line : Shape 74 {
75 public override void Draw() 76 {
77 Console.WriteLine(“直线我已经画好!”);
78 }
79
80 public override void Accept(ShapeVisitor visitor) 81 {
82 visitor.Visit(this);
83 }
84 }
85
86 //结构对象角色
87 internal class AppStructure 88 {
89 private ShapeVisitor _visitor; 90
91 public AppStructure(ShapeVisitor visitor) 92 {
93 this._visitor = visitor; 94 }
95
96 public void Process(Shape shape) 97 {
98 shape.Accept(_visitor);
99 } 100 } 101
102 class Program 103 { 104 static void Main(string[] args) 105 { 106 //如果想执行新增加的操作
107 ShapeVisitor visitor = new CustomVisitor(); 108 AppStructure app = new AppStructure(visitor); 109
110 Shape shape = new Rectangle(); 111 shape.Draw();//执行自己的操作
112 app.Process(shape);//执行新的操作
113
114
115 shape = new Circle(); 116 shape.Draw();//执行自己的操作
117 app.Process(shape);//执行新的操作
118
119
120 shape = new Line(); 121 shape.Draw();//执行自己的操作
122 app.Process(shape);//执行新的操作
123
124
125 Console.ReadLine(); 126 } 127 } 128 }

复制代码

   

5.10、备忘录模式(Memento Pattern):该模式注重封装对象状态变化,支持状态保存、恢复。现实生活中的手机通讯录备忘录,操作系统备份,数据库备份等都是备忘录模式的应用。

       动机(Motivate):在软件构建过程中,某些对象的状态在转换的过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。如何实现对象状态的良好保存与恢复,但同时又不会因此而破坏对象本身的封装性?

       意图(Intent):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态(如果没有这个关键点,其实深拷贝就可以解决问题)。这样以后就可以将该对象恢复到原先保存的状态。

       具体的结构图如下所示

          

       代码实例

复制代码

1 namespace MementoPattern 2 {
3 // 联系人–需要备份的数据,是状态数据,没有操作
4 public sealed class ContactPerson 5 {
6 //姓名
7 public string Name { get; set; }
8
9 //电话号码
10 public string MobileNumber { get; set; }
11 }
12
13 // 发起人–相当于【发起人角色】Originator
14 public sealed class MobileBackOriginator 15 {
16 // 发起人需要保存的内部状态
17 private List _personList; 18
19
20 public List ContactPersonList 21 {
22 get
23 {
24 return this._personList;
25 }
26
27 set
28 {
29 this._personList = value; 30 }
31 }
32 //初始化需要备份的电话名单
33 public MobileBackOriginator(List personList) 34 {
35 if (personList != null)
36 {
37 this._personList = personList; 38 }
39 else
40 {
41 throw new ArgumentNullException(“参数不能为空!”);
42 }
43 }
44
45 // 创建备忘录对象实例,将当期要保存的联系人列表保存到备忘录对象中
46 public ContactPersonMemento CreateMemento() 47 {
48 return new ContactPersonMemento(new List(this._personList));
49 }
50
51 // 将备忘录中的数据备份还原到联系人列表中
52 public void RestoreMemento(ContactPersonMemento memento) 53 {
54 this.ContactPersonList = memento.ContactPersonListBack; 55 }
56
57 public void Show() 58 {
59 Console.WriteLine(“联系人列表中共有{0}个人,他们是:”, ContactPersonList.Count);
60 foreach (ContactPerson p in ContactPersonList) 61 {
62 Console.WriteLine(“姓名: {0} 号码: {1}”, p.Name, p.MobileNumber);
63 }
64 }
65 }
66
67 // 备忘录对象,用于保存状态数据,保存的是当时对象具体状态数据–相当于【备忘录角色】Memeto
68 public sealed class ContactPersonMemento 69 {
70 // 保存发起人创建的电话名单数据,就是所谓的状态
71 public List ContactPersonListBack { get; private set; }
72
73 public ContactPersonMemento(List personList) 74 {
75 ContactPersonListBack = personList; 76 }
77 }
78
79 // 管理角色,它可以管理【备忘录】对象,如果是保存多个【备忘录】对象,当然可以对保存的对象进行增、删等管理处理—相当于【管理者角色】Caretaker
80 public sealed class MementoManager 81 {
82 //如果想保存多个【备忘录】对象,可以通过字典或者堆栈来保存,堆栈对象可以反映保存对象的先后顺序
83 //比如:public Dictionary<string, ContactPersonMemento> ContactPersonMementoDictionary { get; set; }
84 public ContactPersonMemento ContactPersonMemento { get; set; }
85 }
86
87 class Program 88 {
89 static void Main(string[] args)
90 {
91 List persons = new List()
92 {
93 new ContactPerson() { Name=”黄飞鸿”, MobileNumber = “13533332222”},
94 new ContactPerson() { Name=”方世玉”, MobileNumber = “13966554433”},
95 new ContactPerson() { Name=”洪熙官”, MobileNumber = “13198765544”}
96 };
97
98 //手机名单发起人
99 MobileBackOriginator mobileOriginator = new MobileBackOriginator(persons); 100 mobileOriginator.Show(); 101
102 // 创建备忘录并保存备忘录对象
103 MementoManager manager = new MementoManager(); 104 manager.ContactPersonMemento = mobileOriginator.CreateMemento(); 105
106 // 更改发起人联系人列表
107 Console.WriteLine(“-—移除最后一个联系人——–”); 108 mobileOriginator.ContactPersonList.RemoveAt(2); 109 mobileOriginator.Show(); 110
111 // 恢复到原始状态
112 Console.WriteLine(“-——恢复联系人列表——“); 113 mobileOriginator.RestoreMemento(manager.ContactPersonMemento); 114 mobileOriginator.Show(); 115
116 Console.Read(); 117 } 118 } 119 }

复制代码

   

5.11、解释器模式(Interpreter Pattern):该模式注重封装特定领域变化,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。C#的编译器,中英翻译工具,正则表达式都是解释器应用的很好例子。

       动机(Motivate):在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。

       意图(Intent):给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。

       具体的结构图如下所示

                           

六、总结

    C#版本23种面向对象的设计模式,终于写完了,今天是一个总结性的文章。各个模式都列了出来,每个模式的【动机】、【意图】和【结构图】也写了出来,可以方便大家查看。重新自己写了一遍,感觉很多都不一样了。理解更深刻了,学无止境,继续前进吧。

之前写过Python的设计模式,由于经常不使用Python,回过头来再看Python的设计模式,有时候感觉并不是那么的显而易见,所以使用c#重新将代码编写一遍,更加清晰明了。

这里借用原来的介绍,对模式做简要说明,模式简易说明和类图,请查看 http://www.cnblogs.com/cotton/category/606629.html

设计模式分为三种类型

  • 创建型模式:简单工厂、工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式

  • 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

  • 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。


创建型模式

一、简单工厂模式

模式说明

简单工厂模式又称之为静态工厂方法,属于创建型模式。在简单工厂模式中,可以根据传递的参数不同,返回不同类的实例。简单工厂模式定义了一个类,这个类专门用于创建其他类的实例,这些被创建的类都有一个共同的父类。

模式结构图

代码示例

namespace DesignPattern
{ public class SimpleFactory
{ public static Operation GetOperation(op op, double a, double b)
{ switch (op)
{ case op.add: return new Add(a, b); case op.sub: return new Sub(a, b); case op.mul: return new Mul(a, b); case op.div: return new Div(a, b); default: return new undef(a, b);
}
}
} public enum op
{
add = ‘+’,
sub = ‘-‘,
mul = ‘*‘,
div = ‘/‘ } public abstract class Operation
{ public double a, b; public Operation(double a, double b)
{ this.a = a; this.b = b;
} public abstract double GetResult();
} public class Add : Operation
{ public Add(double a, double b) : base(a, b) { } public override double GetResult()
{ return a + b;
}
} public class Sub : Operation
{ public Sub(double a, double b) : base(a, b) { } public override double GetResult()
{ return a - b;
}
} public class Mul : Operation
{ public Mul(double a, double b) : base(a, b) { } public override double GetResult()
{ return a * b;
}
} public class Div : Operation
{ public Div(double a, double b) : base(a, b) { } public override double GetResult()
{ try { return a / b;
} catch (DivideByZeroException e)
{ throw e;
}
}
} public class undef : Operation
{ public undef(double a, double b) : base(a, b) { } public override double GetResult()
{ throw new NotImplementedException();
}

}

}

View Code

二、工厂方法模式

模式说明

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式让实例化推迟到子类。

和简单工厂区别在于,每个工厂只管生产自己对应的产品,而简单工厂是一个工厂生产各种产品。

模式结构图

代码示例

namespace DesignPattern
{ public interface ILogger
{ void write(string log);
} public class EventLogger : ILogger
{ public void write(string log)
{
Console.WriteLine(“EventLog:” + log);
}
} public class FileLogger : ILogger
{ public void write(string log)
{
Console.WriteLine(“FileLog:” + log);
}
} public interface ILoggerFactory
{
ILogger CreateLogger();
} public class EventLoggerFactory : ILoggerFactory
{ public ILogger CreateLogger()
{ return new EventLogger();
}
} public class FileLoggerFactory : ILoggerFactory
{ public ILogger CreateLogger()
{ return new FileLogger();
}
}
}

View Code

三、抽象工厂模式

模式说明

抽象工厂模式提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。

抽象工厂允许客户端使用抽象的接口来创建一组相关的产品,而不需要关系实际产出的具体产品是什么。这样一来,客户就可以从具体的产品中被解耦。

和工厂方法主要区别于,抽象工厂内要像像定义中说的一样,‘创建一组相关的产品’。

感觉像是(不知道这样理解对否):简单工厂是一个工厂生产多个产品;工厂方法是拆分成子工厂,分别生产各自产品;抽象工厂整合工厂方法和简单工厂,随着子工厂规模变大,也可以生产多个类似产品。

模式结构图

代码示例

namespace DesignPattern
{ //抽象实体
public abstract class absSalary
{ protected double salary; protected double bonus; protected double tax; public absSalary(double sal, double bns, double t)
{ this.salary = sal; this.bonus = bns; this.tax = t;
} public abstract double CalculateTax();
} public class ChineseSalary : absSalary
{ public ChineseSalary(double sal, double bns, double t)
: base(sal, bns, t)
{
} public override double CalculateTax()
{ return (base.salary + base.bonus - 3500) * base.tax;
}
} public class ForeignerSalary : absSalary
{ public ForeignerSalary(double sal, double bonus, double tax)
: base(sal, bonus, tax)
{
} public override double CalculateTax()
{ return (base.salary + base.bonus - 4000) * base.tax;
}
} public abstract class absSocialSecurity
{ protected double SocialSecurity; public absSocialSecurity()
{ this.SocialSecurity = 0;
} public virtual double GetSocialSecurity()
{ return this.SocialSecurity;
}
} public class ChineseSocialSecurity : absSocialSecurity
{ public ChineseSocialSecurity(double socialsecurity)
: base()
{ base.SocialSecurity = socialsecurity < 1000 ? 1000 : socialsecurity;
}
} public class ForeignerSocialSecurity : absSocialSecurity
{ public ForeignerSocialSecurity(double socialsecurity)
: base()
{ base.SocialSecurity = socialsecurity < 1500 ? 1500 : socialsecurity;
}
} //抽象工厂,生产一系列产品(多个Create方法,分别对应不同产品)
public interface AbstractFactory
{
absSalary CreateSalary(double sal, double bonus, double tax);
absSocialSecurity CreateSocialSecurity(double socialsecurity);
} public class ChineseFactory : AbstractFactory
{ public absSalary CreateSalary(double sal, double bonus, double tax)
{ return new ChineseSalary(sal, bonus, tax);
} public absSocialSecurity CreateSocialSecurity(double socialsecurity)
{ return new ChineseSocialSecurity(socialsecurity);
}
} public class ForeignerFactory : AbstractFactory
{ public absSalary CreateSalary(double sal, double bonus, double tax)
{ return new ForeignerSalary(sal, bonus, tax);
} public absSocialSecurity CreateSocialSecurity(double socialsecurity)
{ return new ForeignerSocialSecurity(socialsecurity);
}
}
}

View Code

四、创建者模式

模式说明

建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式构建复杂对象就像造汽车一样,是一个一个组件一个一个步骤创建出来的,它允许用户通过制定的对象类型和内容来创建他们,但是用户并不需要知道这个复杂对象是如何构建的,它只需要明白通过这样做我可以得到一个完整的复杂对象实例。

和工厂方法很像,创造者是一个builder内每个方法分别创建产品零部件,而工厂方法是每个factory生产一个产品。如果把builder的零部件当做一个完整产品呢?是不是就像 builder又再一次封装了factory~ 

模式结构图

代码示例

namespace DesignPattern
{ public class Meal
{ private string food; private string drink; public Meal() { } public void setFood(string food)
{ this.food = food;
} public void setDrink(string drink)
{ this.drink = drink;
} public string getFood()
{ return this.food;
} public string getDrink()
{ return this.drink;
}
} //建造者,分别建造不同部件,然后返回整体
public abstract class Builder
{ protected Meal meal = new Meal(); public abstract void buildFood(); public abstract void buildDrink(); public Meal GetMeal()
{ return meal;
}
} public class MealABuilder : Builder
{ public override void buildFood()
{
meal.setFood(“A food”);
} public override void buildDrink()
{
meal.setDrink(“A drink”);
}
} public class MealBBuilder : Builder
{ public override void buildFood()
{
meal.setFood(“B food”);
} public override void buildDrink()
{
meal.setDrink(“B drink”);
}
} public class Waitor
{ public void PrepareMeal(Builder builder)
{
builder.buildDrink();
builder.buildFood();
}
}
}

View Code

五、原型模式

模式说明

所谓原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

说到复制,就会有深/浅两种复制,这是面向对象的值类型和引用类型的差异,具体不作说明

模式结构图

代码示例

namespace DesignPattern
{
[Serializable] public class other
{ public int value { get; set; } public other()
{
value = 10;
}
}

\[Serializable\] public abstract class ColorPrototype
{ public int red { get; set; } public int green { get; set; } public int blue { get; set; } public other o = new other(); //浅拷贝
    public virtual ColorPrototype Clone()
    { return (ColorPrototype)this.MemberwiseClone();
    }
} public class Red : ColorPrototype
{ public override ColorPrototype Clone()
    { return base.Clone();
    }
}

\[Serializable\] public class Green : ColorPrototype
{ public override ColorPrototype Clone()
    {
        BinaryFormatter formatter \= new BinaryFormatter();
        MemoryStream stream \= new MemoryStream();
        formatter.Serialize(stream, this);
        stream.Position \= 0;
        ColorPrototype obj \= (ColorPrototype)formatter.Deserialize(stream); return obj;
    }
}

}

View Code

六、单例模式

代码示例

namespace DesignPattern
{ public class Singleton
{ private int cnt = 0; private static Singleton instance = null; private volatile static Singleton safeInstance = null; private static readonly object lockedobj = new object(); private Singleton()
{
} public static Singleton GetInstance()
{ if (instance == null) instance = new Singleton(); return instance;
} public static Singleton GetSafeInstance()
{ if (safeInstance == null)
{ lock (lockedobj)
{ if (safeInstance == null)
{
safeInstance = new Singleton();
}
}
} return safeInstance;
} public void count()
{
cnt += 1;
} public int getCnt()
{ return cnt;
}
}

}

View Code


结构型模式

七、适配器模式

模式说明

适配器模式就是将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

在适配器模式中,我们可以定义一个包装类,包装不兼容接口的对象,这个包装类就是适配器,它所包装的对象就是适配者。

适配器提供给客户需要的接口,适配器的实现就是将客户的请求转换成对适配者的相应的接口的引用。也就是说,当客户调用适配器的方法时,适配器方法内部将调用 适配者的方法,客户并不是直接访问适配者的,而是通过调用适配器方法访问适配者。因为适配器可以使互不兼容的类能够“合作愉快”。

模式结构图

代码示例

注:此处ILogger接口使用了【工厂方法模式】定义的接口

namespace DesignPattern
{ public interface IAdaptor
{ void writelog(string log);
} public class LogAdaptor : IAdaptor
{
ILogger logger; public LogAdaptor(ILogger logger)
{ this.logger = logger;
} public void writelog(string log)
{ this.logger.write(log);
}
}
}

View Code

八、桥接模式

模式说明

桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。

桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。

个人感觉,代理模式、适配器模式和桥接模式相类似,代理模式是一个代理对外表示一个特定的类,适配器模式相当于一个适配器代理多个类,而桥接模式则更加适用于多个对多个的时候

模式结构图

代码示例

namespace DesignPattern
{ public abstract class Color
{ public string name { get; set; }
} public abstract class Shape
{ private Color color; public string name { get; set; } public void SetColor(Color c)
{
color = c;
} public void Draw()
{
Console.WriteLine(“draw shape {0} with color {1}”, this.name, this.color.name);
}
} public class White : Color
{ public White()
{ this.name = “white”;
}
} public class Blue : Color
{ public Blue()
{ this.name = “blue”;
}
} public class Squre : Shape
{ public Squre()
{ this.name = “squre”;
}
} public class Circle : Shape
{ public Circle()
{ this.name = “circle”;
}
}
}

View Code

九、装饰者模式

模式说明

装饰者模式装饰者模式可以动态地给一个对象增加一些额外的职责。就增加功能来说,装饰者模式相比生成子类更为灵活。

模式结构图

代码示例

namespace DesignPattern
{ public abstract class Car
{ public string color { get; set; } public int compartment { get; set; } public void run()
{
Console.WriteLine(color + “ “ + compartment + “ compartment “ + this.GetType().Name + “ is running!”);
}
} public class Benz:Car
{ public Benz()
{ base.color = “black”; base.compartment = 1;
}
} public class QQ:Car
{ public QQ()
{ base.color = “black”; base.compartment = 1;
}
} public abstract class Decorator : Car
{ public Car car; public Decorator(Car car)
{ this.car = car;
}
} public class ColorDecorator:Decorator
{ //一般在构造函数内完成属性的修改(装饰),这里单独加了一个decorate方法
public ColorDecorator(Car car):base(car)
{
} public Car decorate(string color)
{ base.car.color = color; return base.car;
}
} public class CompartmentDecorator : Decorator
{ public CompartmentDecorator(Car car)
: base(car)
{
} public Car decorate(int compartment)
{ base.car.compartment = compartment; return base.car;
}
}
}

View Code

十、组合模式

模式说明

组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。

组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。同时它也模糊了简单元素(叶 子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。

模式结构图

代码示例

namespace DesignPattern
{ public abstract class File
{ protected string name; public File(string name)
{ this.name = name;
} public abstract void Display();
} public class Folder : File
{
IList list; public Folder(string name)
: base(name)
{
list = new List();
} public void AddFile(File file)
{
list.Add(file);
} public void RemoveFile(File file)
{
list.Remove(file);
} public override void Display()
{
Console.WriteLine(“folder:” + this.name); foreach (File f in list)
{
f.Display();
}
}
} public class ImageFile : File
{ public ImageFile(string name)
: base(name)
{
} public override void Display()
{
Console.WriteLine(“ImageFile:” + this.name);
}
}
}

View Code

十一、外观模式

模式说明

所谓外观模式就是提供一个统一的接口,用来访问子系统中的一群接口。

模式结构图

代码示例

namespace DesignPattern
{ public class Facade
{
Light _light = new Light();
TV _tv = new TV(); public void off()
{
_light.on();
_tv.off();
} public void on()
{
_tv.on();
_light.off();
}
} class Light
{ public void on()
{
Console.WriteLine(“light on!”);
} public void off()
{
Console.WriteLine(“light off!”);
}
} class TV
{ public void on()
{
Console.WriteLine(“tv on!”);
} public void off()
{
Console.WriteLine(“tv off!”);
}
}
}

View Code

十二、享元模式

模式说明

所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。

FlyweightFactory内定义的实体是不变的(共享的),传入参数是状态变化。

缓存形式,传入参数已经被缓存则直接返回,否则创建参数对应实体,放入缓存并返回该新实体

模式结构图

代码示例

namespace DesignPattern
{ public class FlyweightFactory
{ static Dictionary<string, IFlyweight> pendic = new Dictionary<string, IFlyweight>(); public IFlyweight getPen(string color)
{ if (pendic.ContainsKey(color))
{ return pendic[color];
} else {
IFlyweight pen = new ConcreteFlyweight(color);
pendic.Add(color, pen); return pen;
}
} public void Display()
{ foreach (KeyValuePair<string,IFlyweight> pair in pendic)
{
Console.WriteLine(pair.Value.GetType().FullName + “:” + pair.Key);
}
}
} public interface IFlyweight
{ string GetColor();
}; public class ConcreteFlyweight : IFlyweight
{ string color; public ConcreteFlyweight(string color)
{ this.color = color;
} public string GetColor()
{ return this.color;
}
}
}

View Code

十三、代理模式

模式说明

代理模式就是给一个对象提供一个代理,并由代理对象控制对原对象的引用。

在代理模式中,“第三者”代理主要是起到一个中介的作用,它连接客户端和目标对象。

模式结构图

代码示例

namespace DesignPattern
{ public class Girl
{ public string name { get; set; } public Girl(string name)
{ this.name = name;
}
} public class Boy
{ private Girl girl; public string name { get; set; } public Boy(string name, Girl girl)
{ this.name = name; this.girl = girl;
} public void GiveFlower()
{
Console.WriteLine(“boy {0} give flower to girl {1}”, this.name, this.girl.name);
}
} public class Proxy
{ private Boy boy; public Proxy(Boy boy)
{ this.boy = boy;
} public void GiveFlower()
{ this.boy.GiveFlower();
}
}
}

View Code


行为型模式

十四、迭代器模式

代码示例

namespace DesignPattern
{ public class Persons : IEnumerable
{ string[] m_Names; public Persons(params string[] Names)
{
m_Names = new string[Names.Length];

        Names.CopyTo(m\_Names, 0);
    } public IEnumerator GetEnumerator()
    { foreach (string s in m\_Names)
        { yield return s;
        }
    } public int Length { get { return m\_Names.Length; } } public string this\[int i\]
    { get { return m\_Names\[i\];
        } set {
            m\_Names\[i\] \= value;
        }
    }
}

}

View Code

十五、解释器模式

模式说明

所谓解释器(Interpreter)就是将一系列指令转化成代码,能够执行的代码。Interpreter本来就有翻译的意思。GoF给它的定义是:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

模式结构图

代码示例

namespace DesignPattern
{ public class Context
{ private string msg; public Context(string msg)
{ this.msg = msg;
} public string GetMsg()
{ return this.msg;
}
} public interface Interpreter
{ string Interprete(Context context);
} public class UpperInterpreter : Interpreter
{ public string Interprete(Context context)
{ string msg = context.GetMsg(); return msg.ToUpperInvariant();
}
} public class LowerInterpreter : Interpreter
{ public string Interprete(Context context)
{ string msg = context.GetMsg(); return msg.ToLowerInvariant();
}
}
}

View Code

十六、命令模式

模式说明

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

模式结构图

代码示例

namespace DesignPattern
{ //接受命令的对象
public class CDMachine
{ public void on()
{
Console.WriteLine(“CD Machine turns on!”);
} public void off()
{
Console.WriteLine(“CD Machine turns off!”);
}
} //定义命令
public abstract class Command
{ public abstract void Execute(CDMachine cdMachine);
} public class TurnonCommand : Command
{ public override void Execute(CDMachine cdMachine)
{
cdMachine.on();
}
} public class TurnoffCommand : Command
{ public override void Execute(CDMachine cdMachine)
{
cdMachine.off();
}
} //发送命令的对象
public class Controller
{ //遥控的功能 — 可发送的命令
private TurnonCommand turnonCommand; private TurnoffCommand turnoffCommand; public Controller(TurnonCommand turnonCommand, TurnoffCommand turnoffCommand)
{ this.turnonCommand = turnonCommand; this.turnoffCommand = turnoffCommand;
} public void turnOn(CDMachine cdMachine)
{ this.turnonCommand.Execute(cdMachine);
} public void turnOff(CDMachine cdMachine)
{ this.turnoffCommand.Execute(cdMachine);
}
}
}

View Code

十七、中介者模式

模式说明

所谓中介者模式就是用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

模式结构图

代码示例

namespace DesignPattern
{ public abstract class Person
{ public string name; public Mediator mediator; public Person(string name, Mediator mediator)
{ this.name = name; this.mediator = mediator;
} public void Contact(string msg)
{ //参数 this 代表 消息来自我
this.mediator.SendMsg(msg, this);
} internal void GetMsg(string msg)
{
Console.WriteLine(this.name + “ 收到消息:” + msg);
}
} public class HouseOwner : Person
{ public HouseOwner(string name, Mediator mediator) : base(name, mediator) { }
} public class Tenant : Person
{ public Tenant(string name, Mediator mediator) : base(name, mediator) { }
} public interface Mediator
{ void SendMsg(string msg, Person p);
} public class ConcreteMediator : Mediator
{
HouseOwner houseOwner;
Tenant tenant; public ConcreteMediator()
{
} public void SetHouseOwner(HouseOwner houseOwner)
{ this.houseOwner = houseOwner;
} public void SetTenant(Tenant tenant)
{ this.tenant = tenant;
} public void SendMsg(string msg, Person p)
{ if (p.GetType() == houseOwner.GetType())
{
tenant.GetMsg(msg);
} else {
houseOwner.GetMsg(msg);
}
}
}
}

View Code

十八、备忘录模式

模式说明

所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

模式结构图

代码示例

namespace DesignPattern
{ public class Memonto
{ public int blood { get; set; } public int magic { get; set; }
} public class Caretaker
{ private Memonto memonto; public void SetMemonto(Memonto memonto)
{ this.memonto = memonto;
} public Memonto getMemonto()
{ return this.memonto;
}
} public class Original
{ public int blood { get; set; } public int magic { get; set; } public Memonto SaveMemonto()
{ return new Memonto() { blood = this.blood, magic = this.magic };
} public void RestoreMemonto(Memonto memonto)
{ this.blood = memonto.blood; this.magic = memonto.magic;
} public void display()
{
Console.WriteLine(“blood:” + this.blood + “\tmagic:” + this.magic);
}
}
}

View Code

十九、观察者模式

模式说明

定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,当主题对象状态发生变化时会通知所有观察者。

模式结构图

代码示例

public interface Observer
{ void Update(Subject subject);
} public abstract class Subject
{
List obsList = new List(); public void AddObserver(Observer observer)
{
obsList.Add(observer);
} public void RemoveObserver(Observer observer)
{
obsList.Remove(observer);
} public void notity()
{ foreach (Observer o in obsList)
{
o.Update(this);
}
} private string _state; public void SetState(string state)
{ this._state = state;
} public string GetState()
{ return this._state;
}
} public class ConcreteSubject : Subject
{
} public class ConcreteObserver1 : Observer
{ public void Update(Subject subject)
{
Console.WriteLine(“ConcreteObserver1 get notice:” + subject.GetState());
}
} public class ConcreteObserver2 : Observer
{ public void Update(Subject subject)
{
Console.WriteLine(“ConcreteObserver2 get notice:” + subject.GetState());
}
}

View Code

//事件委托的方式
public delegate void updateDelegate(Subject subject); public class EventSubjet : Subject
{ public event updateDelegate UpdateHandler; public void EventNotify()
{
OnUpdate();
} private void OnUpdate()
{ if (UpdateHandler != null)
{
UpdateHandler(this);
}
}
}

View Code

二十、状态模式

模式说明

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

模式结构图

代码示例

namespace DesignPattern
{ public interface IState
{ void display();
} public class WorkState:IState
{ public void display()
{
Console.WriteLine(“Working State”);
}
} public class RestState:IState
{ public void display()
{
Console.WriteLine(“Rest State”);
}
} public class Programmer
{
IState _state; public void Doing(DateTime dt)
{ if(dt.Hour<7 || dt.Hour > 22)
{
_state = new RestState();
} else {
_state = new WorkState();
}
_state.display();
}
}
}

View Code

二十一、模板模式

模式说明

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

模式结构图

代码示例

namespace DesignPattern
{ public abstract class Template
{ protected void boilWater()
{
Console.WriteLine(“boil water”);
} protected virtual void brew()
{
Console.WriteLine(“brew”);
} protected void pourInCup()
{
Console.WriteLine(“pour into cup”);
} protected virtual void addOther()
{
Console.WriteLine(“add other”);
} public void makeBeverage()
{
boilWater();
brew();
pourInCup();
addOther();
}
} public class Tea : Template
{ protected override void brew()
{
Console.WriteLine(“tea”);
} protected override void addOther()
{
Console.WriteLine(“add lemon”);
}
} public class Coffee : Template
{ protected override void brew()
{
Console.WriteLine(“coffee”);
} protected override void addOther()
{
Console.WriteLine(“add sugar”);
}
}
}

View Code

二十二、策略模式

模式说明

定义算法家族并且分别封装,它们之间可以相互替换而不影响客户端。

模式结构图

代码示例

namespace DesignPattern
{ public abstract class OrderStrategy
{ public List<int> orderList; public abstract void Order(); public void display()
{ foreach (int i in orderList)
{
Console.Write(i + “\t”);
}
Console.WriteLine();
}
} public class BubbleStrategy : OrderStrategy
{ public override void Order()
{ for (int i = 0; i < orderList.Count; i++)
{ for (int j = i + 1; j < orderList.Count; j++)
{ if (orderList[i] < orderList[j])//冒泡降序 小的冒上去
{ int temp = orderList[i];
orderList[i] = orderList[j];
orderList[j] = temp;
}
}
}
}
} public class SelectionStrategy : OrderStrategy
{ public override void Order()
{ for (int i = 0; i < orderList.Count; i++)
{ int smallvalue = orderList[i]; int smallposition = i; for (int j = i + 1; j < orderList.Count; j++)
{ if (orderList[j] < smallvalue)
{
smallposition = j;
smallvalue = orderList[j];
}
} //将最小值放到当前要排序的位置
orderList[smallposition] = orderList[i];
orderList[i] = smallvalue;
}
}
} public class InsertionStrategy : OrderStrategy
{ public override void Order()
{ for (int i = 1; i < orderList.Count; i++)
{ int temp = orderList[i];//当前要插入的值,相当于位置I是个空白位置,供对比进行后移
int j = i; //j之前的序列已经排序好,选一个位置把当前值插入

            while (j > 0)
            { //i从1开始,是因为这里j要比较前一个值
                if (temp < orderList\[j - 1\]) //插入过程中,每次比较的值大于当前值则向后移动

{
orderList[j] = orderList[j-1];
j--;
} else { break;
}
} //找到位置(break)或者循环正常结束(说明当前值最小)则赋值。
orderList[j] = temp;
}
}
} public class StrategyManager
{
OrderStrategy strategy; public void SetStrategy(OrderStrategy strategy)
{ this.strategy =strategy;
} public void Sort(List<int> list)
{ this.strategy.orderList = list; this.strategy.Order(); this.strategy.display();
}
}
}

View Code

二十三、访问者模式

模式说明

访问者模式即表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

模式结构图

代码示例

namespace DesignPattern
{ public interface Element
{ void accept(Visitor visitor);
} public class ConcreteElementA : Element
{ string name; public void SetName(string name)
{ this.name = name;
} public string GetName()
{ return this.name;
} public void accept(Visitor visitor)
{
visitor.visitElementA(this);
}
} public class ConcreteElementB : Element
{ int ID; public void SetID(int id)
{ this.ID = id;
} public int GetID()
{ return this.ID;
} public void accept(Visitor visitor)
{
visitor.visitElementB(this);
}
} public interface Visitor
{ void visitElementA(ConcreteElementA ea); void visitElementB(ConcreteElementB eb);
} public class ConcreteVisitorA : Visitor
{ public void visitElementA(ConcreteElementA ea)
{
Console.WriteLine(“ConcreteVisitorA visit ElemantA:” + ea.GetName());
} public void visitElementB(ConcreteElementB eb)
{
Console.WriteLine(“ConcreteVisitorA visit ElemantB:” + eb.GetID());
}
} public class ConcreteVisitorB : Visitor
{ public void visitElementA(ConcreteElementA ea)
{
Console.WriteLine(“ConcreteVisitorB visit ElemantA:” + ea.GetName());
} public void visitElementB(ConcreteElementB eb)
{
Console.WriteLine(“ConcreteVisitorB visit ElemantB:” + eb.GetID());
}
} public class objectStructure
{
List elementlist = new List(); public void Attach(Element e)
{
elementlist.Add(e);
} public void Dettach(Element e)
{
elementlist.Remove(e);
} public void Accept(Visitor visit)
{ foreach(Element e in elementlist)
{
e.accept(visit);
}
}
}
}

View Code

二十四、责任链模式

模式说明

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止,这就是职责链模式。

模式结构图

代码示例

namespace DesignPattern
{ public class Request
{ int days; string name; public Request(int days, string name)
{ this.days = days; this.name = name;
} public int GetDays()
{ return days;
} public string GetName()
{ return name;
}

} public abstract class Responsibility
{ protected Responsibility responsibility; public Responsibility(Responsibility responsibility)
    { this.responsibility = responsibility;
    } public abstract void HandleRequest(Request request);
} public class Leader : Responsibility
{ public Leader(Responsibility responsibility)
        : base(responsibility)
    { } public override void HandleRequest(Request request)
    { if (request.GetDays() < 3)
        {
            Console.WriteLine("Leader passed {0}'s {1} days request", request.GetName(), request.GetDays());
        } else { this.responsibility.HandleRequest(request);
        }
    }
} public class Department : Responsibility
{ public Department(Responsibility responsibility)
        : base(responsibility)
    { } public override void HandleRequest(Request request)
    { if (request.GetDays() < 8)
        {
            Console.WriteLine("Department passed {0}'s {1} days request", request.GetName(), request.GetDays());
        } else { this.responsibility.HandleRequest(request);
        }
    }
} //责任链终端必须处理
public class Boss : Responsibility
{ public Boss() : base(null) { } public override void HandleRequest(Request request)
    { if (request.GetDays() < 15)
        {
            Console.WriteLine("Boss passed {0}'s {1} days request", request.GetName(), request.GetDays());
        } else {
            Console.WriteLine("Boss refused {0}'s {1} days request", request.GetName(), request.GetDays());
        }
    }
}

}

View Code

主程序(注:调用顺序与该列表顺序不一致)

namespace DesignPattern
{ class Program
{ static void Main(string[] args)
{ //简单工厂
Console.WriteLine(“简单工厂”);
Console.WriteLine(SimpleFactory.GetOperation(op.add, 1.1, 2.2).GetResult()); //工厂方法
Console.WriteLine(“\n工厂方法”);
ILoggerFactory factorymethod = new EventLoggerFactory();
ILogger iLogger = factorymethod.CreateLogger();
iLogger.write(“123”);

        factorymethod \= new FileLoggerFactory();
        iLogger \= factorymethod.CreateLogger();
        iLogger.write("321"); //抽象工厂
        Console.WriteLine("\\n抽象工厂");
        AbstractFactory absFactory \= new ChineseFactory();
        absSalary chSalary \= absFactory.CreateSalary(10000, 8000, 0.12);
        absSocialSecurity chScSc \= absFactory.CreateSocialSecurity(1200);
        Console.WriteLine(chSalary.CalculateTax());
        Console.WriteLine(chScSc.GetSocialSecurity());

        absFactory \= new ForeignerFactory();
        chSalary \= absFactory.CreateSalary(10000, 8000, 0.12);
        chScSc \= absFactory.CreateSocialSecurity(1200);
        Console.WriteLine(chSalary.CalculateTax());
        Console.WriteLine(chScSc.GetSocialSecurity()); //创造者模式
        Console.WriteLine("\\n创造者模式");
        Waitor waiter \= new Waitor();
        Builder b1 \= new MealABuilder();
        Builder b2 \= new MealBBuilder();

        waiter.PrepareMeal(b1);
        Meal ma \= b1.GetMeal();
        Console.WriteLine(ma.getFood() \+ "\\t" + ma.getDrink());

        waiter.PrepareMeal(b2);
        Meal mb \= b2.GetMeal();
        Console.WriteLine(mb.getFood() \+ "\\t" + mb.getDrink()); //原型模式
        Console.WriteLine("\\n原型模式");
        Red r \= new Red();
        r.o.value \= 20;//改变引用值
        ColorPrototype RCopy = r.Clone();
        RCopy.o.value \= 30;
        Console.WriteLine(r.o.value);//30 浅拷贝,指向同一个应用对象,一处改变,都改变

Green g = new Green();
g.o.value = 20;
ColorPrototype GCopy = g.Clone();
GCopy.o.value = 30;
Console.WriteLine(g.o.value);//20 深拷贝,引用对象独立 //单例模式
Console.WriteLine(“\n单例模式”);
Task[] tArr = new Task[]{
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count()),
Task.Run(() => Singleton.GetInstance().count())
};
Singleton.GetInstance().count();
Task.WaitAll(tArr);
Console.WriteLine(“danger:” + Singleton.GetInstance().getCnt());

        Task\[\] tArrSafe \= new Task\[\]{
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count()),
        Task.Run(() \=> Singleton.GetSafeInstance().count())
        };
        Singleton.GetSafeInstance().count();
        Task.WaitAll(tArrSafe);
        Console.WriteLine("safe:" + Singleton.GetSafeInstance().getCnt()); //迭代器
        Console.WriteLine("\\n迭代器");
        Persons ps \= new Persons(new string\[\] { "1", "2", "3" }); foreach (string name in ps)
        {
            Console.WriteLine(name);
        } for (var i = 0; i < ps.Length; i++)
        {
            Console.WriteLine(ps\[i\]);
        } //适配器模式
        Console.WriteLine("\\n适配器模式");
        EventLogger eLog \= new EventLogger();
        FileLogger fLog \= new FileLogger();
        LogAdaptor adapter \= new LogAdaptor(eLog);
        adapter.writelog("123123");
        adapter \= new LogAdaptor(fLog);
        adapter.writelog("123123"); //代理模式
        Console.WriteLine("\\n代理模式");
        Girl girl \= new Girl("Han MeiMei");
        Boy boy \= new Boy("Li Lei", girl);
        Proxy proxy \= new Proxy(boy);
        proxy.GiveFlower(); //桥接模式
        Console.WriteLine("\\n桥接模式");
        Color blue \= new Blue();
        Color white \= new White();
        Shape squre \= new Squre();
        Shape circle \= new Circle();
        squre.SetColor(blue);
        squre.Draw();
        circle.SetColor(white);
        circle.Draw(); //组合模式
        Console.WriteLine("\\n组合模式");
        Folder folder1 \= new Folder("study");
        File img \= new ImageFile("img");
        folder1.AddFile(img);
        Folder folder2 \= new Folder("c#");
        folder2.AddFile(img);
        folder1.AddFile(folder2);
        folder1.Display(); //解释器模式
        Console.WriteLine("\\n解释器模式");
        Context context \= new Context("ABcdeFG");
        UpperInterpreter ui \= new UpperInterpreter(); string inprResut = ui.Interprete(context);
        Console.WriteLine("up:" + inprResut);

        LowerInterpreter li \= new LowerInterpreter();
        inprResut \= li.Interprete(context);
        Console.WriteLine("low:" + inprResut); //外观模式
        Console.WriteLine("\\n外观模式");
        Facade facade \= new Facade();
        Console.WriteLine("电视打开,电灯关闭!");
        facade.on();
        Console.WriteLine("3秒后电灯打开,电视关闭");
        Thread.Sleep(3000);
        facade.off(); //享元模式
        Console.WriteLine("\\n享元模式");
        FlyweightFactory flyfactory \= new FlyweightFactory();
        IFlyweight flyweidht \= flyfactory.getPen("red");
        Console.WriteLine(flyweidht.GetColor());
        flyweidht \= flyfactory.getPen("blue");
        Console.WriteLine(flyweidht.GetColor());
        flyweidht \= flyfactory.getPen("red");
        Console.WriteLine(flyweidht.GetColor());
        flyfactory.Display(); //责任链模式
        Console.WriteLine("\\n责任链模式");
        Request request \= new Request(20, "wang");
        Boss boss \= new Boss();
        Department department \= new Department(boss);
        Leader leader \= new Leader(department);
        leader.HandleRequest(request); //命令模式
        Console.WriteLine("\\n命令模式");
        CDMachine cd \= new CDMachine();
        TurnoffCommand off \= new TurnoffCommand();
        TurnonCommand on \= new TurnonCommand();
        Controller ctrl \= new Controller(on, off); //遥控器发送命令到cd机

ctrl.turnOn(cd);
ctrl.turnOff(cd); //中介者模式
Console.WriteLine(“\n中介者模式”); //中介单独存在 //Mediator mediator = new ConcreteMediator();
ConcreteMediator mediator = new ConcreteMediator(); //房主和租客寻找中介
HouseOwner houseOwner = new HouseOwner(“houseowner”, mediator);
Tenant tenant = new Tenant(“tenant”, mediator); //中介给他们搭建链接
mediator.SetHouseOwner(houseOwner);
mediator.SetTenant(tenant);

        houseOwner.Contact("出租房");
        tenant.Contact("租房"); //备忘录模式
        Console.WriteLine("\\n备忘录模式");
        Caretaker caretaker \= new Caretaker();
        Original original \= new Original();
        original.blood \= 100;
        original.magic \= 100;
        original.display();
        caretaker.SetMemonto(original.SaveMemonto());
        original.blood \= 50;
        original.magic \= 50;
        original.display();
        original.RestoreMemonto(caretaker.getMemonto());
        original.display(); //观察者模式
        Console.WriteLine("\\n观察者模式");
        Subject subject \= new ConcreteSubject();
        subject.SetState("start");
        Observer o1 \= new ConcreteObserver1();
        Observer o2 \= new ConcreteObserver2();
        subject.AddObserver(o1);
        subject.AddObserver(o2);
        subject.notity();
        subject.SetState("change");
        subject.notity(); //Subject eventSubject = new EventSubjet();
        EventSubjet eventSubject = new EventSubjet();
        eventSubject.UpdateHandler += o1.Update;
        eventSubject.UpdateHandler += o2.Update;
        eventSubject.SetState("event");
        eventSubject.EventNotify(); //状态模式
        Console.WriteLine("\\n状态模式");
        Programmer programmer \= new Programmer();
        Console.WriteLine(DateTime.Now \+ "程序员正在做什么呢?");
        programmer.Doing(DateTime.Now);
        Console.WriteLine(DateTime.Now.AddHours(\-10) + "程序员正在做什么呢?");
        programmer.Doing(DateTime.Now.AddHours(\-10)); //策略模式
        Console.WriteLine("\\n策略模式");
        BubbleStrategy bubble \= new BubbleStrategy();
        SelectionStrategy selection \= new SelectionStrategy();
        InsertionStrategy insertion \= new InsertionStrategy(); var list = new List<int\>() { 3, 1, 6, 2, 5 };
        StrategyManager manager \= new StrategyManager();
        manager.SetStrategy(bubble);
        manager.Sort(list);
        manager.SetStrategy(selection);
        manager.Sort(list);
        manager.SetStrategy(insertion);
        manager.Sort(list); //模板模式
        Console.WriteLine("\\n模板模式");
        Template tea \= new Tea();
        tea.makeBeverage();
        Template coffee \= new Coffee();
        coffee.makeBeverage(); //访问者模式
        Console.WriteLine("\\n访问者模式");
        ConcreteElementA elementA \= new ConcreteElementA();
        elementA.SetName("ea");
        ConcreteElementB elementB \= new ConcreteElementB();
        elementB.SetID(2);
        objectStructure structure \= new objectStructure();
        structure.Attach(elementA);
        structure.Attach(elementB);

        Visitor visitorA \= new ConcreteVisitorA();
        Visitor visitorB \= new ConcreteVisitorB();

        structure.Accept(visitorA);
        structure.Accept(visitorB); //装饰者模式
        Console.WriteLine("\\n装饰者模式");
        Car car \= new Benz();
        car \= new ColorDecorator(car).decorate("red");
        car.run();
        car \= new CompartmentDecorator(car).decorate(3);
        car.run();
    }
}

}

View Code


该博文出发点是使用面向对象的语言,使用简单的示例简要概括说明各个模式的应用,已备不时之需。

提交了一次竟然没通过,从首页移除

重新发送一遍,是不是能通过呢? 

 为避免某某些折叠代码不能正常打开,附源码下载地址

  经过这段时间对设计模式的学习,自己的感触还是很多的,因为我现在在写代码的时候,经常会想想这里能不能用什么设计模式来进行重构。所以,学完设计模式之后,感觉它会慢慢地影响到你写代码的思维方式。这里对设计模式做一个总结,一来可以对所有设计模式进行一个梳理,二来可以做一个索引来帮助大家收藏。

  PS: 其实,很早之前我就看过所有的设计模式了,但是并没有写博客,但是不久就很快忘记了,也没有起到什么作用,这次以博客的形式总结出来,发现效果还是很明显的,因为通过这种总结的方式,我对它理解更深刻了,也记住的更牢靠了,也影响了自己平时实现功能的思维。所以,我鼓励大家可以通过做笔记的方式来把自己学到的东西进行梳理,这样相信可以理解更深,更好,我也会一直写下来,之后打算写WCF一系列文章。

  其实WCF内容很早也看过了,并且博客园也有很多前辈写的很好,但是,我觉得我还是需要自己总结,因为只有这样,知识才是自己的,别人写的多好,你看了之后,其实还是别人了,所以鼓励大家几点(对于这几点,也是对自己的一个提醒):

  1. 要动手实战别人博客中的例子;
  2. 实现之后进行总结,可以写博客也可以自己记录云笔记等;
  3. 想想能不能进行扩展,进行举一反三。

系列导航:

C#设计模式(1)——单例模式

C#设计模式(2)——简单工厂模式

C#设计模式(3)——工厂方法模式

C#设计模式(4)——抽象工厂模式

C#设计模式(5)——建造者模式(Builder Pattern)

C#设计模式(6)——原型模式(Prototype Pattern)

C#设计模式(7)——适配器模式(Adapter Pattern)

C#设计模式(8)——桥接模式(Bridge Pattern)

C#设计模式(9)——装饰者模式(Decorator Pattern)

  C#设计模式(10)——组合模式(Composite Pattern)

  C#设计模式(11)——外观模式(Facade Pattern)

  C#设计模式(12)——享元模式(Flyweight Pattern)

  C#设计模式(13)——代理模式(Proxy 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#设计模式(20)——策略者模式(Stragety Pattern)

  C#设计模式(21)——责任链模式

  C#设计模式(22)——访问者模式(Vistor Pattern)

  C#设计模式(23)——备忘录模式(Memento Pattern)

  使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性。并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则、开放封闭原则、里氏代替原则、依赖倒置原则、接口隔离原则、合成复用原则和迪米特法则。下面就分别介绍了每种设计原则。

2.1 单一职责原则

  就一个类而言,应该只有一个引起它变化的原因。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会影响到其他的职责,另外,把多个职责耦合在一起,也会影响复用性。

2.2 开闭原则(Open-Closed Principle)

  开闭原则即OCP(Open-Closed Principle缩写)原则,该原则强调的是:一个软件实体(指的类、函数、模块等)应该对扩展开放,对修改关闭。即每次发生变化时,要通过添加新的代码来增强现有类型的行为,而不是修改原有的代码。

  符合开闭原则的最好方式是提供一个固有的接口,然后让所有可能发生变化的类实现该接口,让固定的接口与相关对象进行交互。

2.3 里氏代替原则(Liskov Substitution Principle)

  Liskov Substitution Principle,LSP(里氏代替原则)指的是子类必须替换掉它们的父类型。也就是说,在软件开发过程中,子类替换父类后,程序的行为是一样的。只有当子类替换掉父类后,此时软件的功能不受影响时,父类才能真正地被复用,而子类也可以在父类的基础上添加新的行为。为了就来看看违反了LSP原则的例子,具体代码如下所示:

复制代码

public class Rectangle
{ public virtual long Width { get; set; } public virtual long Height { get; set; }
} // 正方形
public class Square : Rectangle
{ public override long Height
{ get { return base.Height;
} set { base.Height = value; base.Width = value;
}
} public override long Width
{ get { return base.Width;
} set { base.Width = value; base.Height = value;
}
}
} class Test
{ public void Resize(Rectangle r)
{ while (r.Height >= r.Width)
{
r.Width += 1;
}
} var r = new Square() { Width = 10, Height = 10 }; new Test().Resize(r);
}

复制代码

  上面的设计,正如上面注释的一样,在执行SmartTest的resize方法时,如果传入的是长方形对象,当高度大于宽度时,会自动增加宽度直到超出高度。但是如果传入的是正方形对象,则会陷入死循环。此时根本原因是,矩形不能作为正方形的父类,既然出现了问题,可以进行重构,使它们俩都继承于四边形类。重构后的代码如下所示:

复制代码

// 四边形
public abstract class Quadrangle
{ public virtual long Width { get; set; } public virtual long Height { get; set; }
} // 矩形
public class Rectangle : Quadrangle
{ public override long Height { get; set; } public override long Width { get; set; }

} // 正方形
public class Square : Quadrangle
{ public long \_side; public Square(long side)
    {
        \_side \= side;
    }
} class Test
{ public void Resize(Quadrangle r)
    { while (r.Height >= r.Width)
        {
            r.Width += 1;
        }
    } static void Main(string\[\] args)
    { var s = new Square(10); new Test().Resize(s);
    }
}

复制代码

2.4 依赖倒置原则

  依赖倒置(Dependence Inversion Principle, DIP)原则指的是抽象不应该依赖于细节,细节应该依赖于抽象,也就是提出的 “面向接口编程,而不是面向实现编程”。这样可以降低客户与具体实现的耦合。

2.5 接口隔离原则

  接口隔离原则(Interface Segregation Principle, ISP)指的是使用多个专门的接口比使用单一的总接口要好。也就是说不要让一个单一的接口承担过多的职责,而应把每个职责分离到多个专门的接口中,进行接口分离。过于臃肿的接口是对接口的一种污染。

2.6 合成复用原则

  合成复用原则(Composite Reuse Principle, CRP)就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分。新对象通过向这些对象的委派达到复用已用功能的目的。简单地说,就是要尽量使用合成/聚合,尽量不要使用继承。

  要使用好合成复用原则,首先需要区分”Has—A”和“Is—A”的关系。

  “Is—A”是指一个类是另一个类的“一种”,是属于的关系,而“Has—A”则不同,它表示某一个角色具有某一项责任。导致错误的使用继承而不是聚合的常见的原因是错误地把“Has—A”当成“Is—A”.例如:

实际上,雇员、经历、学生描述的是一种角色,比如一个人是“经理”必然是“雇员”。在上面的设计中,一个人无法同时拥有多个角色,是“雇员”就不能再是“学生”了,这显然不合理,因为现在很多在职研究生,即使雇员也是学生。

  上面的设计的错误源于把“角色”的等级结构与“人”的等级结构混淆起来了,误把“Has—A”当作”Is—A”。具体的解决方法就是抽象出一个角色类:

2.7 迪米特法则

  迪米特法则(Law of Demeter,LoD)又叫最少知识原则(Least Knowledge Principle,LKP),指的是一个对象应当对其他对象有尽可能少的了解。也就是说,一个模块或对象应尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立,这样当一个模块修改时,影响的模块就会越少,扩展起来更加容易。

  关于迪米特法则其他的一些表述有:只与你直接的朋友们通信;不要跟“陌生人”说话。

  外观模式(Facade Pattern)和中介者模式(Mediator Pattern)就使用了迪米特法则。

   创建型模式就是用来创建对象的模式,抽象了实例化的过程。所有的创建型模式都有两个共同点。第一,它们都将系统使用哪些具体类的信息封装起来;第二,它们隐藏了这些类的实例是如何被创建和组织的。创建型模式包括单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。

  • 单例模式:解决的是实例化对象的个数的问题,比如抽象工厂中的工厂、对象池等,除了Singleton之外,其他创建型模式解决的都是 new 所带来的耦合关系。
  • 抽象工厂:创建一系列相互依赖对象,并能在运行时改变系列。
  • 工厂方法:创建单个对象,在Abstract Factory有使用到。
  • 原型模式:通过拷贝原型来创建新的对象。

  工厂方法,抽象工厂, 建造者都需要一个额外的工厂类来负责实例化“一个对象”,而Prototype则是通过原型(一个特殊的工厂类)来克隆“易变对象”。

  下面详细介绍下它们。

3.1  单例模式

   单例模式指的是确保某一个类只有一个实例,并提供一个全局访问点。解决的是实体对象个数的问题,而其他的建造者模式都是解决new所带来的耦合关系问题。其实现要点有:

  • 类只有一个实例。问:如何保证呢?答:通过私有构造函数来保证类外部不能对类进行实例化
  • 提供一个全局的访问点。问:如何实现呢?答:创建一个返回该类对象的静态方法

  单例模式的结构图如下所示:

3.2 工厂方法模式

   工厂方法模式指的是定义一个创建对象的工厂接口,由其子类决定要实例化的类,将实际创建工作推迟到子类中。它强调的是”单个对象“的变化。其实现要点有:

  • 定义一个工厂接口。问:如何实现呢?答:声明一个工厂抽象类
  • 由其具体子类创建对象。问:如何去实现呢?答:创建派生于工厂抽象类,即由具体工厂去创建具体产品,既然要创建产品,自然需要产品抽象类和具体产品类了。

  其具体的UML结构图如下所示:

  在工厂方法模式中,工厂类与具体产品类具有平行的等级结构,它们之间是一一对应关系。

3.3 抽象工厂模式

   抽象工厂模式指的是提供一个创建一系列相关或相互依赖对象的接口,使得客户端可以在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象,强调的是”系列对象“的变化。其实现要点有:

  • 提供一系列对象的接口。问:如何去实现呢?答:提供多个产品的抽象接口
  • 创建多个产品族中的多个产品对象。问:如何做到呢?答:每个具体工厂创建一个产品族中的多个产品对象,多个具体工厂就可以创建多个产品族中的多个对象了。

  具体的UML结构图如下所示:

  

3.4 建造者模式

   建造者模式指的是将一个产品的内部表示与产品的构造过程分割开来,从而可以使一个建造过程生成具体不同的内部表示的产品对象。强调的是产品的构造过程。其实现要点有:

  • 将产品的内部表示与产品的构造过程分割开来。问:如何把它们分割开呢?答:不要把产品的构造过程放在产品类中,而是由建造者类来负责构造过程,产品的内部表示放在产品类中,这样不就分割开了嘛。

  具体的UML结构图如下所示:

  

3.5 原型工厂模式

   原型模式指的是通过给出一个原型对象来指明所要创建的对象类型,然后用复制的方法来创建出更多的同类型对象。其实现要点有:

  • 给出一个原型对象。问:如何办到呢?答:很简单嘛,直接给出一个原型类就好了。
  • 通过复制的方法来创建同类型对象。问:又是如何实现呢?答:.NET可以直接调用MemberwiseClone方法来实现浅拷贝

  具体的UML结构图如下所示:

   结构型模式,顾名思义讨论的是类和对象的结构 ,主要用来处理类或对象的组合。它包括两种类型,一是类结构型模式,指的是采用继承机制来组合接口或实现;二是对象结构型模式,指的是通过组合对象的方式来实现新的功能。它包括适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式和代理模式。

  • 适配器模式注重转换接口,将不吻合的接口适配对接 
  • 桥接模式注重分离接口与其实现,支持多维度变化 
  • 组合模式注重统一接口,将“一对多”的关系转化为“一对一”的关系 
  • 装饰者模式注重稳定接口,在此前提下为对象扩展功能 
  • 外观模式注重简化接口,简化组件系统与外部客户程序的依赖关系 
  • 享元模式注重保留接口,在内部使用共享技术对对象存储进行优化 
  • 代理模式注重假借接口,增加间接层来实现灵活控制

4.1 适配器模式

   适配器模式意在转换接口,它能够使原本不能再一起工作的两个类一起工作,所以经常用来在类库的复用、代码迁移等方面。例如DataAdapter类就应用了适配器模式。适配器模式包括类适配器模式和对象适配器模式,具体结构如下图所示,左边是类适配器模式,右边是对象适配器模式。

4.2 桥接模式

   桥接模式旨在将抽象化与实现化解耦,使得两者可以独立地变化。意思就是说,桥接模式把原来基类的实现化细节再进一步进行抽象,构造到一个实现化的结构中,然后再把原来的基类改造成一个抽象化的等级结构,这样就可以实现系统在多个维度的独立变化,桥接模式的结构图如下所示。

4.3 装饰者模式

   装饰者模式又称包装(Wrapper)模式,它可以动态地给一个对象添加一些额外的功能,装饰者模式较继承生成子类的方式更加灵活。虽然装饰者模式能够动态地将职责附加到对象上,但它也会造成产生一些细小的对象,增加了系统的复杂度。具体的结构图如下所示。

4.4 组合模式

   组合模式又称为部分—整体模式。组合模式将对象组合成树形结构,用来表示整体与部分的关系。组合模式使得客户端将单个对象和组合对象同等对待。如在.NET中WinForm中的控件,TextBox、Label等简单控件继承与Control类,同时GroupBox这样的组合控件也是继承于Control类。组合模式的具体结构图如下所示。

4.5 外观模式

  在系统中,客户端经常需要与多个子系统进行交互,这样导致客户端会随着子系统的变化而变化,此时可以使用外观模式把客户端与各个子系统解耦。外观模式指的是为子系统中的一组接口提供一个一致的门面,它提供了一个高层接口,这个接口使子系统更加容易使用。如电信的客户专员,你可以让客户专员来完成冲话费,修改套餐等业务,而不需要自己去与各个子系统进行交互。具体类结构图如下所示:

4.6 享元模式

   在系统中,如何我们需要重复使用某个对象时,此时如果重复地使用new操作符来创建这个对象的话,这对系统资源是一个极大的浪费,既然每次使用的都是同一个对象,为什么不能对其共享呢?这也是享元模式出现的原因。

  享元模式运用共享的技术有效地支持细粒度的对象,使其进行共享。在.NET类库中,String类的实现就使用了享元模式,String类采用字符串驻留池的来使字符串进行共享。更多内容参考博文:http://www.cnblogs.com/artech/archive/2010/11/25/internedstring.html。享元模式的具体结构图如下所示。

4.7 代理模式

   在系统开发中,有些对象由于网络或其他的障碍,以至于不能直接对其访问,此时可以通过一个代理对象来实现对目标对象的访问。如.NET中的调用Web服务等操作。

  代理模式指的是给某一个对象提供一个代理,并由代理对象控制对原对象的访问。具体的结构图如下所示。

  

  注:外观模式、适配器模式和代理模式区别?

  解答:这三个模式的相同之处是,它们都是作为客户端与真实被使用的类或系统之间的一个中间层,起到让客户端间接调用真实类的作用,不同之处在于,所应用的场合和意图不同。

  代理模式与外观模式主要区别在于,代理对象无法直接访问对象,只能由代理对象提供访问,而外观对象提供对各个子系统简化访问调用接口,而适配器模式则不需要虚构一个代理者,目的是复用原有的接口。外观模式是定义新的接口,而适配器则是复用一个原有的接口。

  另外,它们应用设计的不同阶段,外观模式用于设计的前期,因为系统需要前期就需要依赖于外观,而适配器应用于设计完成之后,当发现设计完成的类无法协同工作时,可以采用适配器模式。然而很多情况下在设计初期就要考虑适配器模式的使用,如涉及到大量第三方应用接口的情况;代理模式是模式完成后,想以服务的方式提供给其他客户端进行调用,此时其他客户端可以使用代理模式来对模块进行访问。

  总之,代理模式提供与真实类一致的接口,旨在用来代理类来访问真实的类,外观模式旨在简化接口,适配器模式旨在转换接口。

   行为型模式是对在不同对象之间划分责任和算法的抽象化。行为模式不仅仅关于类和对象,还关于它们之间的相互作用。行为型模式又分为类的行为模式和对象的行为模式两种。

  • 类的行为模式——使用继承关系在几个类之间分配行为。
  • 对象的行为模式——使用对象聚合的方式来分配行为。

  行为型模式包括11种模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、状态模式、策略模式、责任链模式、访问者模式、解释器模式和备忘录模式。

  • 模板方法模式:封装算法结构,定义算法骨架,支持算法子步骤变化。
  • 命令模式:注重将请求封装为对象,支持请求的变化,通过将一组行为抽象为对象,实现行为请求者和行为实现者之间的解耦。
  • 迭代器模式:注重封装特定领域变化,支持集合的变化,屏蔽集合对象内部复杂结构,提供客户程序对它的透明遍历。
  • 观察者模式:注重封装对象通知,支持通信对象的变化,实现对象状态改变,通知依赖它的对象并更新。
  • 中介者模式:注重封装对象间的交互,通过封装一系列对象之间的复杂交互,使他们不需要显式相互引用,实现解耦。
  • 状态模式:注重封装与状态相关的行为,支持状态的变化,通过封装对象状态,从而在其内部状态改变时改变它的行为。
  • 策略模式:注重封装算法,支持算法的变化,通过封装一系列算法,从而可以随时独立于客户替换算法。
  • 责任链模式:注重封装对象责任,支持责任的变化,通过动态构建职责链,实现事务处理。
  • 访问者模式:注重封装对象操作变化,支持在运行时为类结构添加新的操作,在类层次结构中,在不改变各类的前提下定义作用于这些类实例的新的操作。
  • 备忘录模式:注重封装对象状态变化,支持状态保存、恢复。
  • 解释器模式:注重封装特定领域变化,支持领域问题的频繁变化,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。

5.1 模板方法模式

   在现实生活中,有论文模板,简历模板等。在现实生活中,模板的概念是给定一定的格式,然后其他所有使用模板的人可以根据自己的需求去实现它。同样,模板方法也是这样的。

  模板方法模式是在一个抽象类中定义一个操作中的算法骨架,而将一些具体步骤实现延迟到子类中去实现。模板方法使得子类可以不改变算法结构的前提下,重新定义算法的特定步骤,从而达到复用代码的效果。具体的结构图如下所示。

以生活中做菜为例子实现的模板方法结构图

5.2 命令模式

   命令模式属于对象的行为模式,命令模式把一个请求或操作封装到一个对象中,通过对命令的抽象化来使得发出命令的责任和执行命令的责任分隔开。命令模式的实现可以提供命令的撤销和恢复功能。具体的结构图如下所示。

5.3 迭代器模式

   迭代器模式是针对集合对象而生的,对于集合对象而言,必然涉及到集合元素的添加删除操作,也肯定支持遍历集合元素的操作,此时如果把遍历操作也放在集合对象的话,集合对象就承担太多的责任了,此时可以进行责任分离,把集合的遍历放在另一个对象中,这个对象就是迭代器对象。

  迭代器模式提供了一种方法来顺序访问一个集合对象中各个元素,而又无需暴露该对象的内部表示,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部元素。具体的结构图如下所示。

5.4 观察者模式

   在现实生活中,处处可见观察者模式,例如,微信中的订阅号,订阅博客和QQ微博中关注好友,这些都属于观察者模式的应用。

  观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的行为。具体结构图如下所示:

5.5 中介者模式

   在现实生活中,有很多中介者模式的身影,例如QQ游戏平台,聊天室、QQ群和短信平台,这些都是中介者模式在现实生活中的应用。

  中介者模式,定义了一个中介对象来封装一系列对象之间的交互关系。中介者使各个对象之间不需要显式地相互引用,从而使耦合性降低,而且可以独立地改变它们之间的交互行为。具体的结构图如下所示:

5.6 状态模式

   每个对象都有其对应的状态,而每个状态又对应一些相应的行为,如果某个对象有多个状态时,那么就会对应很多的行为。那么对这些状态的判断和根据状态完成的行为,就会导致多重条件语句,并且如果添加一种新的状态时,需要更改之前现有的代码。这样的设计显然违背了开闭原则,状态模式正是用来解决这样的问题的。

  状态模式——允许一个对象在其内部状态改变时自动改变其行为,对象看起来就像是改变了它的类。具体的结构图如下所示:

5.7 策略模式

   在现实生活中,中国的所得税,分为企业所得税、外商投资企业或外商企业所得税和个人所得税,针对于这3种所得税,每种所计算的方式不同,个人所得税有个人所得税的计算方式,而企业所得税有其对应计算方式。如果不采用策略模式来实现这样一个需求的话,我们会定义一个所得税类,该类有一个属性来标识所得税的类型,并且有一个计算税收的CalculateTax()方法,在该方法体内需要对税收类型进行判断,通过if-else语句来针对不同的税收类型来计算其所得税。这样的实现确实可以解决这个场景,但是这样的设计不利于扩展,如果系统后期需要增加一种所得税时,此时不得不回去修改CalculateTax方法来多添加一个判断语句,这样明白违背了“开放——封闭”原则。此时,我们可以考虑使用策略模式来解决这个问题,既然税收方法是这个场景中的变化部分,此时自然可以想到对税收方法进行抽象,这也是策略模式实现的精髓所在。

  策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象负责。策略模式通常把一系列的算法包装到一系列的策略类里面。用一句话慨括策略模式就是——“将每个算法封装到不同的策略类中,使得它们可以互换”。下面是策略模式的结构图:

  

5.8 责任链模式

   在现实生活中,有很多请求并不是一个人说了就算的,例如面试时的工资,低于1万的薪水可能技术经理就可以决定了,但是1万~1万5的薪水可能技术经理就没这个权利批准,可能需要请求技术总监的批准。

  责任链模式——某个请求需要多个对象进行处理,从而避免请求的发送者和接收之间的耦合关系。将这些对象连成一条链子,并沿着这条链子传递该请求,直到有对象处理它为止。具体结构图如下所示:

5.9 访问者模式

   访问者模式是封装一些施加于某种数据结构之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保存不变。访问者模式适用于数据结构相对稳定的系统, 它把数据结构和作用于数据结构之上的操作之间的耦合度降低,使得操作集合可以相对自由地改变。具体结构图如下所示:

5.10 备忘录模式

   生活中的手机通讯录备忘录,操作系统备份点,数据库备份等都是备忘录模式的应用。备忘录模式是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以把该对象恢复到原先的状态。具体的结构图如下所示:

5.11 解释器模式

   解释器模式是一个比较少用的模式,所以我自己也没有对该模式进行深入研究,在生活中,英汉词典的作用就是实现英文和中文互译,这就是解释器模式的应用。

  解释器模式是给定一种语言,定义它文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释器语言中的句子。具体的结构图如下所示:

   23种设计模式,其实前辈们总结出来解决问题的方式,它们追求的宗旨还是保证系统的低耦合高内聚,指导它们的原则无非就是封装变化,责任单一,面向接口编程等设计原则。之后,我会继续分享自己WCF的学习过程,尽管博客园中有很多WCF系列,之前觉得没必要写,觉得会用就行了,但是不写,总感觉知识不是自己的,感觉没有深入,所以还是想写这样一个系列,希望各位博友后面多多支持。

  PS: 很多论坛都看到初学者问,WCF现在还有没有必要深入学之类的问题,因为他们觉得这些技术可能会过时,说不定到时候微软又推出了一个新的SOA的实现方案了,那岂不是白花时间深入学了,所以就觉得没必要深入去学,知道用就可以了。对于这个问题,我之前也有这样同样的感觉,但是现在我觉得,尽管WCF技术可能会被替换,但深入了解一门技术,重点不是知道一些更高深API的调用啊,而是了解它的实现机制和思维方式,即使后面这个技术被替代了,其背后机制也肯定是相似的。所以深入了解了一个技术,你就会感觉新的技术熟悉,对其感觉放松。并且,你深入了解完一门技术之后,你面试时也敢说你很好掌握了这门技术,而不至于说平时使用的很多,一旦深入问时却不知道背后实现原理。这也是我要写WCF系列的原因。希望这点意见对一些初学者有帮助。

本文源码寄方于github:https://github.com/w392807287/Design\_pattern\_of\_python

参考文献:

《大话设计模式》——吴强

《Python设计模式》——pythontip.com

《23种设计模式》——http://www.cnblogs.com/beijiguangyong/

设计模式是什么?

设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。

起初,你会认为“模式”就是为了解决一类特定问题而特别想出来的明智之举。说的没错,看起来的确是通过很多人一起工作,从不同的角度看待问题进而形成的一个最通用、最灵活的解决方案。也许这些问题你曾经见过或是曾经解决过,但是你的解决方案很可能没有模式这么完备。

虽然被称为“设计模式”,但是它们同“设计“领域并非紧密联系。设计模式同传统意义上的分析、设计与实现不同,事实上设计模式将一个完整的理念根植于程序中,所以它可能出现在分析阶段或是更高层的设计阶段。很有趣的是因为设计模式的具体体现是程序代码,因此可能会让你认为它不会在具体实现阶段之前出现(事实上在进入具体实现阶段之前你都没有意识到正在使用具体的设计模式)。

可以通过程序设计的基本概念来理解模式:增加一个抽象层。抽象一个事物就是隔离任何具体细节,这么做的目的是为了将那些不变的核心部分从其他细节中分离出来。当你发现你程序中的某些部分经常因为某些原因改动,而你不想让这些改动的部分引发其他部分的改动,这时候你就需要思考那些不会变动的设计方法了。这么做不仅会使代码可维护性更高,而且会让代码更易于理解,从而降低开发成本。

这里列举了三种最基本的设计模式:

  1. 创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。
  2. 结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。
  3. 行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

创建型

1. Factory Method(工厂方法)

2. Abstract Factory(抽象工厂)

3. Builder(建造者)

4. Prototype(原型)

5. Singleton(单例)

结构型

6. Adapter Class/Object(适配器)

7. Bridge(桥接)

8. Composite(组合)

9. Decorator(装饰)

10. Facade(外观)

11. Flyweight(享元)

12. Proxy(代理)

行为型

13. Interpreter(解释器)

14. Template Method(模板方法)

15. Chain of Responsibility(责任链)

16. Command(命令)

17. Iterator(迭代器)

18. Mediator(中介者)

19. Memento(备忘录)

20. Observer(观察者)

21. State(状态)

22. Strategy(策略)

23. Visitor(访问者)

创建型

1.Factory Method(工厂方法)

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使个类的实例化延迟到其子类。

适用性:

当一个类不知道它所必须创建的对象的类的时候。

当一个类希望由它的子类来指定它所创建的对象的时候。

当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

class ChinaGetter:

def __init__(``self``):

self``.trans = dict``(dog``=``u``"小狗"``, cat``=``u``"小猫"``)

def get(``self``, msgid):

try``:

return self``.trans[msgid]

except KeyError:

return str``(msgid)

class EnglishGetter:

def get(``self``, msgid):

return str``(msgid)

def get_localizer(language``=``"English"``):

languages = dict``(English``=``EnglishGetter, China``=``ChinaGetter)

return languages[language]()

e, g = get_localizer(``"English"``), get_localizer(``"China"``)

for msgid in "dog parrot cat bear"``.split():

print``(e.get(msgid), g.get(msgid))

2. Abstract Factory(抽象工厂)

意图:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 
适用性:

 一个系统要独立于它的产品的创建、组合和表示时。

 一个系统要由多个产品系列中的一个来配置时。

 当你要强调一系列相关的产品对象的设计以便进行联合使用时。

 当你提供一个产品类库,而只想显示它们的接口而不是实现时。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

import random

class PetShop:

def __init__(``self``, animal_factory``=``None``):

self``.pet_factory = animal_factory

def show_pet(``self``):

pet = self``.pet_factory.get_pet()

print``(``"This is a lovely"``, str``(pet))

print``(``"It says"``, pet.speak())

print``(``"It eats"``, self``.pet_factory.get_food())

class Dog:

def speak(``self``):

return "woof"

def __str__(``self``):

return "Dog"

class Cat:

def speak(``self``):

return "meow"

def __str__(``self``):

return "Cat"

class DogFactory:

def get_pet(``self``):

return Dog()

def get_food(``self``):

return "dog food"

class CatFactory:

def get_pet(``self``):

return Cat()

def get_food(``self``):

return "cat food"

def get_factory():

return random.choice([DogFactory, CatFactory])()

if __name__ =``= "__main__"``:

shop = PetShop()

for i in range``(``3``):

shop.pet_factory = get_factory()

shop.show_pet()

print``(``"=" * 20``)

3. Builder(建造者)

意图:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

适用性:

当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

当构造过程必须允许被构造的对象有不同的表示时。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

class Director(``object``):

def __init__(``self``):

self``.builder = None

def construct_building(``self``):

self``.builder.new_building()

self``.builder.build_floor()

self``.builder.build_size()

def get_building(``self``):

return self``.builder.building

class Builder(``object``):

def __init__(``self``):

self``.building = None

def new_building(``self``):

self``.building = Building()

class BuilderHouse(Builder):

def build_floor(``self``):

self``.building.floor = 'One'

def build_size(``self``):

self``.building.size = 'Big'

class BuilderFlat(Builder):

def build_floor(``self``):

self``.building.floor = 'More than One'

def build_size(``self``):

self``.building.size = 'Small'

class Building(``object``):

def __init__(``self``):

self``.floor = None

self``.size = None

def __repr__(``self``):

return 'Floor: %s | Size: %s' % (``self``.floor, self``.size)

if __name__ =``= "__main__"``:

director = Director()

director.builder = BuilderHouse()

director.construct_building()

building = director.get_building()

print``(building)

director.builder = BuilderFlat()

director.construct_building()

building = director.get_building()

print``(building)

4. Prototype(原型)

意图:

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

适用性:

当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者为了避免创建一个与产品类层次平行的工厂类层次时;或者当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

import copy

class Prototype:

def __init__(``self``):

self``._objects = {}

def register_object(``self``, name, obj):

self``._objects[name] = obj

def unregister_object(``self``, name):

del self``._objects[name]

def clone(``self``, name, *``*``attr):

obj = copy.deepcopy(``self``._objects.get(name))

obj.__dict__.update(attr)

return obj

def main():

class A:

def __str__(``self``):

return "I am A"

a = A()

prototype = Prototype()

prototype.register_object(``'a'``, a)

b = prototype.clone(``'a'``, a``=``1``, b``=``2``, c``=``3``)

print``(a)

print``(b.a, b.b, b.c)

if __name__ =``= '__main__'``:

main()

5. Singleton(单例)

意图:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性:

当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

class Singleton(``object``):

def __new__(``cls``, *``args, *``*``kw):

if not hasattr``(``cls``, '_instance'``):

org = super``(Singleton, cls``)

cls``._instance = org.__new__(``cls``, *``args, *``*``kw)

return cls``._instance

if __name__ =``= '__main__'``:

class SingleSpam(Singleton):

def __init__(``self``, s):

self``.s = s

def __str__(``self``):

return self``.s

s1 = SingleSpam(``'spam'``)

print id``(s1), s1

s2 = SingleSpam(``'spa'``)

print id``(s2), s2

print id``(s1), s1

6. Adapter Class/Object(适配器)

意图:

 将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 

适用性:

 你想使用一个已经存在的类,而它的接口不符合你的需求。

你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。

(仅适用于对象Adapter )你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

import os

class Dog(``object``):

def __init__(``self``):

self``.name = "Dog"

def bark(``self``):

return "woof!"

class Cat(``object``):

def __init__(``self``):

self``.name = "Cat"

def meow(``self``):

return "meow!"

class Human(``object``):

def __init__(``self``):

self``.name = "Human"

def speak(``self``):

return "'hello'"

class Car(``object``):

def __init__(``self``):

self``.name = "Car"

def make_noise(``self``, octane_level):

return "vroom%s" % (``"!" * octane_level)

class Adapter(``object``):

def __init__(``self``, obj, adapted_methods):

self``.obj = obj

self``.__dict__.update(adapted_methods)

def __getattr__(``self``, attr):

return getattr``(``self``.obj, attr)

def main():

objects = []

dog = Dog()

objects.append(Adapter(dog, dict``(make_noise``=``dog.bark)))

cat = Cat()

objects.append(Adapter(cat, dict``(make_noise``=``cat.meow)))

human = Human()

objects.append(Adapter(human, dict``(make_noise``=``human.speak)))

car = Car()

car_noise = lambda``: car.make_noise(``3``)

objects.append(Adapter(car, dict``(make_noise``=``car_noise)))

for obj in objects:

print "A"``, obj.name, "goes"``, obj.make_noise()

if __name__ =``= "__main__"``:

main()

7. Bridge(桥接)

意图:

 将抽象部分与它的实现部分分离,使它们都可以独立地变化。

 适用性:

 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。

 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge 模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。

 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。

 (C++)你想对客户完全隐藏抽象的实现部分。在C++中,类的表示在类接口中是可见的。

 有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分。Rumbaugh 称这种类层次结构为“嵌套的普化”(nested generalizations )。

 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。一个简单的例子便是Coplien 的String 类[ Cop92 ],在这个类中多个对象可以共享同一个字符串表示(StringRep)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

class DrawingAPI1(``object``):

def draw_circle(``self``, x, y, radius):

print``(``'API1.circle at {}:{} radius {}'``.``format``(x, y, radius))

class DrawingAPI2(``object``):

def draw_circle(``self``, x, y, radius):

print``(``'API2.circle at {}:{} radius {}'``.``format``(x, y, radius))

class CircleShape(``object``):

def __init__(``self``, x, y, radius, drawing_api):

self``._x = x

self``._y = y

self``._radius = radius

self``._drawing_api = drawing_api

def draw(``self``):

self``._drawing_api.draw_circle(``self``._x, self``._y, self``._radius)

def scale(``self``, pct):

self``._radius *``= pct

def main():

shapes = (

CircleShape(``1``, 2``, 3``, DrawingAPI1()),

CircleShape(``5``, 7``, 11``, DrawingAPI2())

)

for shape in shapes:

shape.scale(``2.5``)

shape.draw()

if __name__ =``= '__main__'``:

main()

8. Composite(组合)

意图:

 将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性。 

适用性:

 你想表示对象的部分-整体层次结构。

你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

class Component:

def __init__(``self``,strName):

self``.m_strName = strName

def Add(``self``,com):

pass

def Display(``self``,nDepth):

pass

class Leaf(Component):

def Add(``self``,com):

print "leaf can't add"

def Display(``self``,nDepth):

strtemp = "-" * nDepth

strtemp``=``strtemp``+``self``.m_strName

print strtemp

class Composite(Component):

def __init__(``self``,strName):

self``.m_strName = strName

self``.c = []

def Add(``self``,com):

self``.c.append(com)

def Display(``self``,nDepth):

strtemp = "-"``*``nDepth

strtemp``=``strtemp``+``self``.m_strName

print strtemp

for com in self``.c:

com.Display(nDepth``+``2``)

if __name__ =``= "__main__"``:

p = Composite(``"Wong"``)

p.Add(Leaf(``"Lee"``))

p.Add(Leaf(``"Zhao"``))

p1 = Composite(``"Wu"``)

p1.Add(Leaf(``"San"``))

p.Add(p1)

p.Display(``1``);

9. Decorator(装饰)

意图: 动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。 
适用性:

 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

 处理那些可以撤消的职责。

当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

class foo(``object``):

def f1(``self``):

print``(``"original f1"``)

def f2(``self``):

print``(``"original f2"``)

class foo_decorator(``object``):

def __init__(``self``, decoratee):

self``._decoratee = decoratee

def f1(``self``):

print``(``"decorated f1"``)

self``._decoratee.f1()

def __getattr__(``self``, name):

return getattr``(``self``._decoratee, name)

u = foo()

v = foo_decorator(u)

v.f1()

v.f2()

10. Facade(外观)

意图:

 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

适用性:

当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade 可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。

客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade 将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。

当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

import time

SLEEP = 0.5

class TC1:

def run(``self``):

print``(``"###### In Test 1 ######"``)

time.sleep(SLEEP)

print``(``"Setting up"``)

time.sleep(SLEEP)

print``(``"Running test"``)

time.sleep(SLEEP)

print``(``"Tearing down"``)

time.sleep(SLEEP)

print``(``"Test Finished\n"``)

class TC2:

def run(``self``):

print``(``"###### In Test 2 ######"``)

time.sleep(SLEEP)

print``(``"Setting up"``)

time.sleep(SLEEP)

print``(``"Running test"``)

time.sleep(SLEEP)

print``(``"Tearing down"``)

time.sleep(SLEEP)

print``(``"Test Finished\n"``)

class TC3:

def run(``self``):

print``(``"###### In Test 3 ######"``)

time.sleep(SLEEP)

print``(``"Setting up"``)

time.sleep(SLEEP)

print``(``"Running test"``)

time.sleep(SLEEP)

print``(``"Tearing down"``)

time.sleep(SLEEP)

print``(``"Test Finished\n"``)

class TestRunner:

def __init__(``self``):

self``.tc1 = TC1()

self``.tc2 = TC2()

self``.tc3 = TC3()

self``.tests = [i for i in (``self``.tc1, self``.tc2, self``.tc3)]

def runAll(``self``):

[i.run() for i in self``.tests]

if __name__ =``= '__main__'``:

testrunner = TestRunner()

testrunner.runAll()

11. Flyweight(享元)

意图:

运用共享技术有效地支持大量细粒度的对象。

适用性:

一个应用程序使用了大量的对象。

完全由于使用大量的对象,造成很大的存储开销。

对象的大多数状态都可变为外部状态。

如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。 

应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

import weakref

class Card(``object``):

_CardPool = weakref.WeakValueDictionary()

def __new__(``cls``, value, suit):

obj = Card._CardPool.get(value + suit, None``)

if not obj:

obj = object``.__new__(``cls``)

Card._CardPool[value + suit] = obj

obj.value, obj.suit = value, suit

return obj

def __repr__(``self``):

return "<Card: %s%s>" % (``self``.value, self``.suit)

if __name__ =``= '__main__'``:

c1 = Card(``'9'``, 'h'``)

c2 = Card(``'9'``, 'h'``)

print``(c1, c2)

print``(c1 =``= c2)

print``(``id``(c1), id``(c2))

12. Proxy(代理)

意图:

为其他对象提供一种代理以控制对这个对象的访问。

适用性:

 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。下面是一 些可以使用Proxy 模式常见情况: 

1) 远程代理(Remote Proxy )为一个对象在不同的地址空间提供局部代表。 NEXTSTEP[Add94] 使用NXProxy 类实现了这一目的。Coplien[Cop92] 称这种代理为“大使” (Ambassador )。 
2 )虚代理(Virtual Proxy )根据需要创建开销很大的对象。在动机一节描述的ImageProxy 就是这样一种代理的例子。 
3) 保护代理(Protection Proxy )控制对原始对象的访问。保护代理用于对象应该有不同 的访问权限的时候。例如,在Choices 操作系统[ CIRM93]中KemelProxies为操作系统对象提供 了访问保护。 
4 )智能指引(Smart Reference )取代了简单的指针,它在访问对象时执行一些附加操作。 它的典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(也称为SmartPointers[Ede92 ] )。

 当第一次引用一个持久对象时,将它装入内存。

 在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

import time

class SalesManager:

def work(``self``):

print``(``"Sales Manager working..."``)

def talk(``self``):

print``(``"Sales Manager ready to talk"``)

class Proxy:

def __init__(``self``):

self``.busy = 'No'

self``.sales = None

def work(``self``):

print``(``"Proxy checking for Sales Manager availability"``)

if self``.busy =``= 'No'``:

self``.sales = SalesManager()

time.sleep(``2``)

self``.sales.talk()

else``:

time.sleep(``2``)

print``(``"Sales Manager is busy"``)

if __name__ =``= '__main__'``:

p = Proxy()

p.work()

p.busy = 'Yes'

p.work()

13. Interpreter(解释器)

意图:

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

适用性:

当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。

效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

class Context:

def __init__(``self``):

self``.``input``=``""

self``.output``=``""

class AbstractExpression:

def Interpret(``self``,context):

pass

class Expression(AbstractExpression):

def Interpret(``self``,context):

print "terminal interpret"

class NonterminalExpression(AbstractExpression):

def Interpret(``self``,context):

print "Nonterminal interpret"

if __name__ =``= "__main__"``:

context``= ""

c = []

c = c + [Expression()]

c = c + [NonterminalExpression()]

c = c + [Expression()]

c = c + [Expression()]

for a in c:

a.Interpret(context)

14. Template Method(模板方法)

意图:

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

适用性:

一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke 和Johnson所描述过的“重分解以一般化”的一个很好的例子[ OJ93 ]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

控制子类扩展。模板方法只在特定点调用“hook ”操作(参见效果一节),这样就只允许在这些点进行扩展。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

ingredients = "spam eggs apple"

line = '-' * 10

def iter_elements(getter, action):

for element in getter():

action(element)

print``(line)

def rev_elements(getter, action):

for element in getter()[::``-``1``]:

action(element)

print``(line)

def get_list():

return ingredients.split()

def get_lists():

return [``list``(x) for x in ingredients.split()]

def print_item(item):

print``(item)

def reverse_item(item):

print``(item[::``-``1``])

def make_template(skeleton, getter, action):

def template():

skeleton(getter, action)

return template

templates = [make_template(s, g, a)

for g in (get_list, get_lists)

for a in (print_item, reverse_item)

for s in (iter_elements, rev_elements)]

for template in templates:

template()

15. Chain of Responsibility(责任链)

意图:

 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

 适用性:

 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。

 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

 可处理一个请求的对象集合应被动态指定。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

class Handler:

def successor(``self``, successor):

self``.successor = successor

class ConcreteHandler1(Handler):

def handle(``self``, request):

if request > 0 and request <``= 10``:

print``(``"in handler1"``)

else``:

self``.successor.handle(request)

class ConcreteHandler2(Handler):

def handle(``self``, request):

if request > 10 and request <``= 20``:

print``(``"in handler2"``)

else``:

self``.successor.handle(request)

class ConcreteHandler3(Handler):

def handle(``self``, request):

if request > 20 and request <``= 30``:

print``(``"in handler3"``)

else``:

print``(``'end of chain, no handler for {}'``.``format``(request))

class Client:

def __init__(``self``):

h1 = ConcreteHandler1()

h2 = ConcreteHandler2()

h3 = ConcreteHandler3()

h1.successor(h2)

h2.successor(h3)

requests = [``2``, 5``, 14``, 22``, 18``, 3``, 35``, 27``, 20``]

for request in requests:

h1.handle(request)

if __name__ =``= "__main__"``:

client = Client()

16. Command(命令)

意图:

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

适用性:

抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(call back)函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。Command 模式是回调机制的一个面向对象的替代品。

在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。

支持取消操作。Command的Excute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消”和“重做”。

支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。

用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务( transaction)的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

import os

class MoveFileCommand(``object``):

def __init__(``self``, src, dest):

self``.src = src

self``.dest = dest

def execute(``self``):

self``()

def __call__(``self``):

print``(``'renaming {} to {}'``.``format``(``self``.src, self``.dest))

os.rename(``self``.src, self``.dest)

def undo(``self``):

print``(``'renaming {} to {}'``.``format``(``self``.dest, self``.src))

os.rename(``self``.dest, self``.src)

if __name__ =``= "__main__"``:

command_stack = []

command_stack.append(MoveFileCommand(``'foo.txt'``, 'bar.txt'``))

command_stack.append(MoveFileCommand(``'bar.txt'``, 'baz.txt'``))

for cmd in command_stack:

cmd.execute()

for cmd in reversed``(command_stack):

cmd.undo()

17. Iterator(迭代器)

意图:

提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。

适用性:

访问一个聚合对象的内容而无需暴露它的内部表示。

支持对聚合对象的多种遍历。

为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

def count_to(count):

numbers = [``"one"``, "two"``, "three"``, "four"``, "five"``]

for pos, number in zip``(``range``(count), numbers):

yield number

count_to_two = lambda``: count_to(``2``)

count_to_five = lambda``: count_to(``5``)

print``(``'Counting to two...'``)

for number in count_to_two():

print number

print " "

print``(``'Counting to five...'``)

for number in count_to_five():

print number

print " "

18. Mediator(中介者)

意图:

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

适用性:

一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。

一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。

想定制一个分布在多个类中的行为,而又不想生成太多的子类。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

import time

class TC:

def __init__(``self``):

self``._tm = tm

self``._bProblem = 0

def setup(``self``):

print``(``"Setting up the Test"``)

time.sleep(``1``)

self``._tm.prepareReporting()

def execute(``self``):

if not self``._bProblem:

print``(``"Executing the test"``)

time.sleep(``1``)

else``:

print``(``"Problem in setup. Test not executed."``)

def tearDown(``self``):

if not self``._bProblem:

print``(``"Tearing down"``)

time.sleep(``1``)

self``._tm.publishReport()

else``:

print``(``"Test not executed. No tear down required."``)

def setTM(``self``, TM):

self``._tm = tm

def setProblem(``self``, value):

self``._bProblem = value

class Reporter:

def __init__(``self``):

self``._tm = None

def prepare(``self``):

print``(``"Reporter Class is preparing to report the results"``)

time.sleep(``1``)

def report(``self``):

print``(``"Reporting the results of Test"``)

time.sleep(``1``)

def setTM(``self``, TM):

self``._tm = tm

class DB:

def __init__(``self``):

self``._tm = None

def insert(``self``):

print``(``"Inserting the execution begin status in the Database"``)

time.sleep(``1``)

import random

if random.randrange(``1``, 4``) =``= 3``:

return -``1

def update(``self``):

print``(``"Updating the test results in Database"``)

time.sleep(``1``)

def setTM(``self``, TM):

self``._tm = tm

class TestManager:

def __init__(``self``):

self``._reporter = None

self``._db = None

self``._tc = None

def prepareReporting(``self``):

rvalue = self``._db.insert()

if rvalue =``= -``1``:

self``._tc.setProblem(``1``)

self``._reporter.prepare()

def setReporter(``self``, reporter):

self``._reporter = reporter

def setDB(``self``, db):

self``._db = db

def publishReport(``self``):

self``._db.update()

rvalue = self``._reporter.report()

def setTC(``self``, tc):

self``._tc = tc

if __name__ =``= '__main__'``:

reporter = Reporter()

db = DB()

tm = TestManager()

tm.setReporter(reporter)

tm.setDB(db)

reporter.setTM(tm)

db.setTM(tm)

while (``True``):

tc = TC()

tc.setTM(tm)

tm.setTC(tc)

tc.setup()

tc.execute()

tc.tearDown()

19. Memento(备忘录)

意图:

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

适用性:

必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。

如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

import copy

def Memento(obj, deep``=``False``):

state = (copy.copy, copy.deepcopy)[``bool``(deep)](obj.__dict__)

def Restore():

obj.__dict__.clear()

obj.__dict__.update(state)

return Restore

class Transaction:

deep = False

def __init__(``self``, *``targets):

self``.targets = targets

self``.Commit()

def Commit(``self``):

self``.states = [Memento(target, self``.deep) for target in self``.targets]

def Rollback(``self``):

for st in self``.states:

st()

class transactional(``object``):

def __init__(``self``, method):

self``.method = method

def __get__(``self``, obj, T):

def transaction(``*``args, *``*``kwargs):

state = Memento(obj)

try``:

return self``.method(obj, *``args, *``*``kwargs)

except``:

state()

raise

return transaction

class NumObj(``object``):

def __init__(``self``, value):

self``.value = value

def __repr__(``self``):

return '<%s: %r>' % (``self``.__class__.__name__, self``.value)

def Increment(``self``):

self``.value +``= 1

@transactional

def DoStuff(``self``):

self``.value = '1111' 

self``.Increment()

if __name__ =``= '__main__'``:

n = NumObj(``-``1``)

print``(n)

t = Transaction(n)

try``:

for i in range``(``3``):

n.Increment()

print``(n)

t.Commit()

print``(``'-- commited'``)

for i in range``(``3``):

n.Increment()

print``(n)

n.value +``= 'x' 

print``(n)

except``:

t.Rollback()

print``(``'-- rolled back'``)

print``(n)

print``(``'-- now doing stuff ...'``)

try``:

n.DoStuff()

except``:

print``(``'-> doing stuff failed!'``)

import traceback

traceback.print_exc(``0``)

pass

print``(n)

20. Observer(观察者)

意图:

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

适用性:

当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

class Subject(``object``):

def __init__(``self``):

self``._observers = []

def attach(``self``, observer):

if not observer in self``._observers:

self``._observers.append(observer)

def detach(``self``, observer):

try``:

self``._observers.remove(observer)

except ValueError:

pass

def notify(``self``, modifier``=``None``):

for observer in self``._observers:

if modifier !``= observer:

observer.update(``self``)

class Data(Subject):

def __init__(``self``, name``=``''):

Subject.__init__(``self``)

self``.name = name

self``._data = 0

@property

def data(``self``):

return self``._data

@data``.setter

def data(``self``, value):

self``._data = value

self``.notify()

class HexViewer:

def update(``self``, subject):

print``(``'HexViewer: Subject %s has data 0x%x' %

(subject.name, subject.data))

class DecimalViewer:

def update(``self``, subject):

print``(``'DecimalViewer: Subject %s has data %d' %

(subject.name, subject.data))

def main():

data1 = Data(``'Data 1'``)

data2 = Data(``'Data 2'``)

view1 = DecimalViewer()

view2 = HexViewer()

data1.attach(view1)

data1.attach(view2)

data2.attach(view2)

data2.attach(view1)

print``(``"Setting Data 1 = 10"``)

data1.data = 10

print``(``"Setting Data 2 = 15"``)

data2.data = 15

print``(``"Setting Data 1 = 3"``)

data1.data = 3

print``(``"Setting Data 2 = 5"``)

data2.data = 5

print``(``"Detach HexViewer from data1 and data2."``)

data1.detach(view2)

data2.detach(view2)

print``(``"Setting Data 1 = 10"``)

data1.data = 10

print``(``"Setting Data 2 = 15"``)

data2.data = 15

if __name__ =``= '__main__'``:

main()

21. State(状态)

意图:

 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

 适用性:

 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。

 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

class State(``object``):

def scan(``self``):

self``.pos +``= 1

if self``.pos =``= len``(``self``.stations):

self``.pos = 0

print``(``"Scanning... Station is"``, self``.stations[``self``.pos], self``.name)

class AmState(State):

def __init__(``self``, radio):

self``.radio = radio

self``.stations = [``"1250"``, "1380"``, "1510"``]

self``.pos = 0

self``.name = "AM"

def toggle_amfm(``self``):

print``(``"Switching to FM"``)

self``.radio.state = self``.radio.fmstate

class FmState(State):

def __init__(``self``, radio):

self``.radio = radio

self``.stations = [``"81.3"``, "89.1"``, "103.9"``]

self``.pos = 0

self``.name = "FM"

def toggle_amfm(``self``):

print``(``"Switching to AM"``)

self``.radio.state = self``.radio.amstate

class Radio(``object``):

def __init__(``self``):

self``.amstate = AmState(``self``)

self``.fmstate = FmState(``self``)

self``.state = self``.amstate

def toggle_amfm(``self``):

self``.state.toggle_amfm()

def scan(``self``):

self``.state.scan()

if __name__ =``= '__main__'``:

radio = Radio()

actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2

actions = actions * 2

for action in actions:

action()

22. Strategy(策略)

意图:

 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

 适用性:

 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。

 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时[H087] ,可以使用策略模式。

 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。

 一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

import types

class StrategyExample:

def __init__(``self``, func``=``None``):

self``.name = 'Strategy Example 0'        

if func is not None``:

self``.execute = types.MethodType(func, self``)

def execute(``self``):

print``(``self``.name)

def execute_replacement1(``self``):

print``(``self``.name + ' from execute 1'``)

def execute_replacement2(``self``):

print``(``self``.name + ' from execute 2'``)

if __name__ =``= '__main__'``:

strat0 = StrategyExample()

strat1 = StrategyExample(execute_replacement1)

strat1.name = 'Strategy Example 1'    

strat2 = StrategyExample(execute_replacement2)

strat2.name = 'Strategy Example 2'

strat0.execute()

strat1.execute()

strat2.execute()

23. Visitor(访问者)

意图:

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

 适用性:

 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke和Johnson所描述过的“重分解以一般化”的一个很好的例子[OJ93]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

 控制子类扩展。模板方法只在特定点调用“hook ”操作(参见效果一节),这样就只允许在这些点进行扩展。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

class Node(``object``):

pass

class A(Node):

pass

class B(Node):

pass

class C(A, B):

pass

class Visitor(``object``):

def visit(``self``, node, *``args, *``*``kwargs):

meth = None

for cls in node.__class__.__mro__:

meth_name = 'visit_'``+``cls``.__name__

meth = getattr``(``self``, meth_name, None``)

if meth:

break

if not meth:

meth = self``.generic_visit

return meth(node, *``args, *``*``kwargs)

def generic_visit(``self``, node, *``args, *``*``kwargs):

print``(``'generic_visit '``+``node.__class__.__name__)

def visit_B(``self``, node, *``args, *``*``kwargs):

print``(``'visit_B '``+``node.__class__.__name__)

a = A()

b = B()

c = C()

visitor = Visitor()

visitor.visit(a)

visitor.visit(b)

visitor.visit(c)

以上  

欢迎多来访问博客:http://liqiongyu.com/blog

微信公众号: