0%

一、引言

在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用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);

复制代码

六、总结

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

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

本文源码寄方于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

微信公众号:

单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式
例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。

单例模式有 3 个特点:

  • 单例类只有一个实例对象
  • 该单例对象必须由单例类自行创建
  • 单例类对外提供一个访问该单例的全局访问点

单例模式是设计模式中最简单的模式之一。通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。

单例模式的结构

单例模式的主要角色如下:

  • 单例类(Singleton):包含一个实例且能自行创建这个实例的类。
  • 访问类(Client):使用单例的类。

单例模式的实现

Singleton 模式通常有两种实现形式:懒汉式单例、饿汉式单例。

第 1 种:懒汉式单例

该模式的特点是类加载时没有生成单例,只有当第一次调用 Getlnstance 方法时才去创建这个单例。代码如下:

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



public class Singleton
{

private static Singleton instance;


private static readonly object locker = new object();


private Singleton(){ }





public static Singleton GetInstance()
{

if (instance == null)
{
lock (locker)
{

if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}

第 2 种:饿汉式单例

该模式的特点是类一旦加载就创建一个单例,保证在调用 GetInstance 方法之前单例已经存在了。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20



public class Singleton
{

private static Singleton instance=new Singleton();


private Singleton() { }





public static Singleton GetInstance()
{
return instance;
}
}

前面分析了单例模式的结构与特点,以下是它通常适用的场景的特点:

  • 在应用场景中,某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
  • 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
  • 当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。

单例模式可扩展为多例(Multition)模式,这种模式可生成多个实例并保存在 List 中,客户需要时可随机获取,其结构图如图所示:

多例模式可分为以下两种:

  • 有上限多例模式:多例类的实例数目有上限,并把实例的上限当做逻辑的一部分创造到了多例类的内部,这种多例模式叫做有上限多例模式。
  • 无上限多例模式:多例类的实例数目并不需要有上限,实例数目并没有上限的多例模式就叫做无上限多例模式。

原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。

由于 C# 提供了 ICloneable 接口,用 C# 实现原型模式很简单。

模式的结构

原型模式包含以下主要角色:

  • 原型(Prototype):声明一个克隆自身的接口,该角色一般有抽象类(Prototype)、接口(ICloneable)两种实现方式(GOF使用的是抽象类,在C#中个人推荐使用接口)。
  • 具体原型类(ConcretePrototype):实现原型(抽象类或接口)的 Clone() 方法,它是可被复制的对象。
  • 访问类(Client):使用具体原型类中的 Clone() 方法来复制新的对象。

使用接口作为Prototype时,其结构图如图所示(后面全部是接口方式的原型模式实现):

使用抽象类作为Prototype时,其结构图如图所示(来自GOF):

模式的实现

C# 中已经定义了 ICloneable 接口,具体原型类只要实现 ICloneable 接口就可实现对象的克隆(Object有 MemberwiseClone() 方法默认浅克隆),克隆是浅克隆还是深克隆取决于具体原型类 Clone() 的实现。其代码如下:

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

public interface ICloneable
{
Object Clone();
}


public abstract class Prototype
{
public abstract Object Clone();
}


public class ConcretePrototype : ICloneable
{
private int id;
public int Id
{
get { return id; }
}
public ConcretePrototype(int id)
{
this.id = id;
}
public Object Clone()
{
return new ConcretePrototype(id);
}







}


class Program
{
static void Main(string[] args)
{
ConcretePrototype cp1 = new ConcretePrototype(1);
ConcretePrototype cp2 = (ConcretePrototype)cp1.Clone();
Console.WriteLine("cp1的Id为:{0}",cp1.Id);
Console.WriteLine("cp2的Id为:{0}", cp2.Id);
Console.ReadKey();
}
}

运行结果:

1
2
cp1的Id为:1
cp2的Id为:1

原型模式通常适用于以下场景:

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 对象的创建过程比较麻烦,但复制比较简单的时候。

原型模式可扩展为带原型管理器的原型模式,它在原型模式的基础上增加了一个原型管理器 PrototypeManager 类。该类用 Dictionary(或HashMap) 保存多个复制的原型,Client 类可以通过管理器的 Get(String id) 方法从中获取复制的原型。其结构如图所示:

工厂方法(FactoryMethod)模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。

如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背“开闭原则”(可以通过反射克服该缺点)

“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

工厂方法模式的主要优点有:

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程(对创建过程复杂的对象很有作用)
  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

其缺点是:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度

工厂方法模式由抽象工厂、具体工厂、抽象产品和具体产品等4个要素构成。本节来分析其基本结构和实现方法。

模式的结构

工厂方法模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 CreateProduct() 来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

抽象工厂、抽象产品可以是接口,也可以是抽象类。抽象产品的定义方式取决于产品对象的建模事物,抽象工厂的定义方式一般与抽象产品的定义方式保持一致。

一般情况下,产品对象是对现实世界中的事物进行建模,使用抽象类定义抽象产品更合理。特殊情况下,产品对象对功能组件、功能实现建模或产品对象已有父对象(C#中对象只能有一个父类)时则使用接口定义抽象产品。

其结构图如图所示(使用抽象类):

模式的实现

根据上图写出的该模式的代码如下:

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

class Program
{
static void Main(string[] args)
{

Product product1 = new ConcreteFactory1().CreateProduct();
product1.ShowInfo();
Product product2 = new ConcreteFactory2().CreateProduct();
product2.ShowInfo();
Console.ReadKey();
}
}





public abstract class Product
{
public abstract void ShowInfo();
}



public class ConcreteProduct1 : Product
{
public override void ShowInfo()
{
Console.WriteLine("产品类型为Product1");
}
}



public class ConcreteProduct2 : Product
{
public override void ShowInfo()
{
Console.WriteLine("产品类型为Product2");
}
}




public abstract class AbstractFactory
{
public abstract Product CreateProduct();
}



public class ConcreteFactory1 : AbstractFactory
{
public override Product CreateProduct()
{
return new ConcreteProduct1();
}
}



public class ConcreteFactory2 : AbstractFactory
{
public override Product CreateProduct()
{
return new ConcreteProduct2();
}
}

运行结果:

1
2
产品类型为Product1
产品类型为Product2

上述代码,添加新类型的产品,需要新增新产品类和新产品工厂类,工厂父类AbstractFactory不需要修改,这样对于已有的工厂不会产生任何潜在的改动影响——便于扩展。
这种方式和直接new ConcreteProduct1()、new ConcreteProduct2()有点像,只不过由每一种Product自己的工厂类复杂new操作,主要原因如下:

  • new一个Product出来,可能有很多字段都需要赋值,还要运行一些初始化方法。如果这些赋值、方法在客户client类里面写,那么其他所有客户都要写这些代码,代码重复。如果这些赋值、方法写在产品类的构造函数里面,要干的事情特别多,几十行上百行的代码,全放构造函数里面,有点违背设计原则,在构造函数做太复杂的操作,当出错时发现错误有时会很困难。构造函数应该尽量简单,一眼望穿,最好能保证永不出现构造失败的情况。
  • 如果ConcreteProduct1多了一个子类ConcreteProduct1Child,现在生产产品时返回这个类的对象,那么所有客户端的new ConcreteProduct1,都要换成new ConcreteProduct1Child,而如果做成工厂模式,直接在返回ConcreteProduct1的代码哪里更改一下返回ConcreteProduct1Child类的对象就可以了,反正返回的都是Product1(抽象父类)——方便维护
  • 如果所有的产品类,在返回对象之前,又要添加新的逻辑了,那么需要一个个类的找,修改,如果全集中在工厂类中,直接在工厂类中修改即可,避免遗漏,还是——方便维护

如果返回一个实例要做很多事情,不好直接写在构造函数里面,可以写在具体的工厂类里面,而且如果工厂父类要添加新的逻辑,所有工厂同时享有。所以工厂模式主要是有代码重用,分割职责解耦,便于维护的特点。

工厂方法模式通常适用于以下场景:

  • 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
  • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  • 客户不关心创建产品的细节,只关心产品的品牌。

当需要生成的产品不多且不会增加,一个具体工厂类就可以完成任务时,可删除抽象工厂类。这时工厂方法模式将退化到简单工厂模式,其结构图如图所示:

在上面的实现代码上增加简单工厂方法的实现,代码如下:

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

public class SimpleFactory
{
public static Product CreateProduct(string name)
{
Product product = null;
if (name == "ConcreteProduct1")
{
product = new ConcreteProduct1();
}
else if (name == "ConcreteProduct2")
{
product = new ConcreteProduct2();
}
return product;
}
}


public class ReflectionSimpleFactory
{

public static Product CreateProduct(string name)
{

Assembly ass = Assembly.GetCallingAssembly();

AssemblyName assName = new AssemblyName(ass.FullName);

Type t = ass.GetType(assName.Name+"."+name);

Product o = (Product)Activator.CreateInstance(t);
return o;
}
}

C#工厂模式——简单工厂、工厂方法、反射+简单工厂、抽象工厂——CSDN

在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成(如计算机、角色模型),只有建造者模式可以很好地描述该类产品的创建

建造者(Builder)模式的定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。

它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

该模式的主要优点如下:

  • 各个具体的建造者相互独立,有利于系统的扩展。
  • 客户端不必知道产品内部组成的细节,便于控制细节风险。

其缺点如下:

  • 产品的组成部分必须相同,这限制了其使用范围。
  • 如果产品的内部变化复杂,该模式会增加很多的建造者类

建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用

建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成

模式的结构

建造者(Builder)模式的主要角色如下:

  • 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件
  • 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法**GetResult()**。
  • 具体建造者(Concrete Builder)实现Builder接口,完成复杂产品的各个部件的具体创建方法。
  • 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息

其简单结构图如图所示(来自GOF):

其详细结构图如图所示(Part部分可以定义任意个):

1
2
3
4
5
6
7
8
可以代入下面的情景理解:
将访问类看做买房子的客户
将产品看做房子
将指挥者看做建筑商
将抽象建造者看做建房的通用流程
将具体建造者1看做户型1的施工队
将具体建造者2看做户型2的施工队
客户买房子,建筑商会根据客户需求安排对应户型的施工队键房。

模式的实现

上图给出了建造者(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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

public class Product
{
private String partA;
private String partB;
private String partC;
public void SetPartA(String partA)
{
this.partA=partA;
}
public void SetPartB(String partB)
{
this.partB=partB;
}
public void SetPartC(String partC)
{
this.partC=partC;
}
public void Show()
{

}
}


public abstract class Builder
{

protected Product product=new Product();
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract void BuildPartC();

public Product GetResult()
{
return product;
}
}


public class ConcreteBuilder1 : Builder
{
public void BuildPartA()
{
product.SetPartA("建造 PartA");
}
public void BuildPartB()
{
product.SetPartA("建造 PartB");
}
public void BuildPartC()
{
product.SetPartA("建造 PartC");
}
}


public class Director
{
private Builder builder;
public Director(Builder builder)
{
this.builder=builder;
}

public Product Construct()
{
builder.BuildPartA();
builder.BuildPartB();
builder.BuildPartC();
return builder.GetResult();
}
}


class Program
{
static void Main(string[] args)
{
Builder builder=new ConcreteBuilder1();
Director director=new Director(builder);
Product product=director.Construct();
product.Show();
Console.ReadKey();
}
}

建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用:

  • 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的
  • 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的

建造者(Builder)模式在应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色

前面介绍的工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机、计算机软件学院只培养计算机软件专业的学生等。

同种类称为同等级,也就是说:工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。

抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,下图所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图:

抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品

使用抽象工厂模式一般要满足以下条件:

  • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品
  • 系统一次只可能消费其中某一族产品,即同族的产品一起使用

抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下:

  • 可以在工厂类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  • 当增加一个新的产品族时不需要修改原代码,满足开闭原则。

其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改

抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同

模式的结构

抽象工厂模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法CreateProduct(),可以创建多个不同等级的产品
  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系

注:抽象工厂、抽象产品的定义推荐使用抽象类,GOF中也是使用的抽象类。

抽象工厂模式的简化结构图如图所示(来自GOF):

抽象工厂模式的详细结构图如图所示(1、2代表产品族,如海尔、TCL等;A、B代表产品等级,如电视机、空调等):

模式的实现

参考工厂方法的代码实现,增加多个具体工厂、多个抽象产品,部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22



public abstract class AbstractFactory
{
public abstract ProductA CreatProduct();
public abstract ProductB CreatProduct();
}



public class ConcreteFactoryA1 : AbstractFactory
{
public override ProductA CreatProduct()
{
return new ConcreteProductA1();
}
public override ProductB CreatProduct()
{
return new ConcreteProductB1();
}
}

抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如 java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。

抽象工厂模式通常适用于以下场景:

  • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

抽象工厂模式的扩展有一定的“开闭原则”倾斜性:

  • 当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
  • 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。

另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式

C#工厂模式——简单工厂、工厂方法、反射+简单工厂、抽象工厂——CSDN

一、引言

最近在设计模式的一些内容,主要的参考书籍是《Head First 设计模式》,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二同时可以给一些初学设计模式的朋友一些参考。首先我介绍的是设计模式中比较简单的一个模式——单例模式(因为这里只牵涉到一个类)

二、单例模式的介绍

说到单例模式,大家第一反应应该就是——什么是单例模式?,从“单例”字面意思上理解为——一个类只有一个实例,所以单例模式也就是保证一个类只有一个实例的一种实现方法罢了(设计模式其实就是帮助我们解决实际开发过程中的方法, 该方法是为了降低对象之间的耦合度,然而解决方法有很多种,所以前人就总结了一些常用的解决方法为书籍,从而把这本书就称为设计模式),下面给出单例模式的一个官方定义:确保一个类只有一个实例,并提供一个全局访问点。为了帮助大家更好地理解单例模式,大家可以结合下面的类图来进行理解,以及后面也会剖析单例模式的实现思路:

三、为什么会有单例模式

看完单例模式的介绍,自然大家都会有这样一个疑问——为什么要有单例模式的?它在什么情况下使用的?从单例模式的定义中我们可以看出——单例模式的使用自然是当我们的系统中某个对象只需要一个实例的情况,例如:操作系统中只能有一个任务管理器,操作文件时,同一时间内只允许一个实例对其操作等,既然现实生活中有这样的应用场景,自然在软件设计领域必须有这样的解决方案了(因为软件设计也是现实生活中的抽象),所以也就有了单例模式了。

四、剖析单例模式的实现思路

了解完了一些关于单例模式的基本概念之后,下面就为大家剖析单例模式的实现思路的,因为在我自己学习单例模式的时候,咋一看单例模式的实现代码确实很简单,也很容易看懂,但是我还是觉得它很陌生(这个可能是看的少的,或者自己在写代码中也用的少的缘故),而且心里总会这样一个疑问——为什么前人会这样去实现单例模式的呢?他们是如何思考的呢?后面经过自己的琢磨也就慢慢理清楚单例模式的实现思路了,并且此时也不再觉得单例模式陌生了,下面就分享我的一个剖析过程的:

我们从单例模式的概念(确保一个类只有一个实例,并提供一个访问它的全局访问点)入手,可以把概念进行拆分为两部分:(1)确保一个类只有一个实例;(2)提供一个访问它的全局访问点;下面通过采用两人对话的方式来帮助大家更快掌握分析思路:

菜鸟:怎样确保一个类只有一个实例了?

老鸟:那就让我帮你分析下,你创建类的实例会想到用什么方式来创建的呢?

新手:用new关键字啊,只要new下就创建了该类的一个实例了,之后就可以使用该类的一些属性和实例方法了

老鸟:那你想过为什么可以使用new关键字来创建类的实例吗?

菜鸟:这个还有条件的吗?………, 哦,我想起来了,如果类定义私有的构造函数就不能在外界通过new创建实例了(注:有些初学者就会问,有时候我并没有在类中定义构造函数为什么也可以使用new来创建对象,那是因为编译器在背后做了手脚了,当编译器看到我们类中没有定义构造函数,此时编译器会帮我们生成一个公有的无参构造函数)

老鸟:不错,回答的很对,这样你的疑惑就得到解答了啊

菜鸟:那我要在哪里创建类的实例了?

老鸟:你傻啊,当然是在类里面创建了(注:这样定义私有构造函数就是上面的一个思考过程的,要创建实例,自然就要有一个变量来保存该实例把,所以就有了私有变量的声明,但是实现中是定义静态私有变量,朋友们有没有想过——这里为什么定义为静态的呢?对于这个疑问的解释为:每个线程都有自己的线程栈,定义为静态主要是为了在多线程确保类有一个实例

菜鸟:哦,现在完全明白了,但是我还有另一个疑问——现在类实例创建在类内部,那外界如何获得该的一个实例来使用它了?

老鸟:这个,你可以定义一个公有方法或者属性来把该类的实例公开出去了(注:这样就有了公有方法的定义了,该方法就是提供方法问类的全局访问点)

通过上面的分析,相信大家也就很容易写出单例模式的实现代码了,下面就看看具体的实现代码(看完之后你会惊讶道:真是这样的!):

复制代码

///


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

public class Singleton
{ // 定义一个静态变量来保存类的实例
private static Singleton uniqueInstance; // 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
} ///
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 ///

///
public static Singleton GetInstance()
{ // 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new Singleton();
} return uniqueInstance;
}
}

复制代码

 上面的单例模式的实现在单线程下确实是完美的,然而在多线程的情况下会得到多个Singleton实例,因为在两个线程同时运行GetInstance方法时,此时两个线程判断(uniqueInstance ==null)这个条件时都返回真,此时两个线程就都会创建Singleton的实例,这样就违背了我们单例模式初衷了,既然上面的实现会运行多个线程执行,那我们对于多线程的解决方案自然就是使GetInstance方法在同一时间只运行一个线程运行就好了,也就是我们线程同步的问题了(对于线程同步大家也可以参考我线程同步的文章),具体的解决多线程的代码如下:

复制代码

///


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

public class Singleton
{ // 定义一个静态变量来保存类的实例
private static Singleton uniqueInstance; // 定义一个标识确保线程同步
private static readonly object locker = new object(); // 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
} ///
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 ///

///
public static Singleton GetInstance()
{ // 当第一个线程运行到这里时,此时会对locker对象 “加锁”, // 当第二个线程运行该方法时,首先检测到locker对象为”加锁”状态,该线程就会挂起等待第一个线程解锁 // lock语句运行完之后(即线程运行完之后)会对该对象”解锁”
lock (locker)
{ // 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new Singleton();
}
} return uniqueInstance;
}
}

复制代码

上面这种解决方案确实可以解决多线程的问题,但是上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(uniqueInstance==null)为假,此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式的缺陷,我们只需要在lock语句前面加一句(uniqueInstance==null)的判断就可以避免锁所增加的额外开销,这种实现方式我们就叫它 “双重锁定”,下面具体看看实现代码的:

复制代码

///


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

public class Singleton
{ // 定义一个静态变量来保存类的实例
private static Singleton uniqueInstance; // 定义一个标识确保线程同步
private static readonly object locker = new object(); // 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
} ///
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 ///

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

复制代码

五、C#中实现了单例模式的类

 理解完了单例模式之后,菜鸟又接着问了:.NET FrameWork类库中有没有单例模式的实现呢?

经过查看,.NET类库中确实存在单例模式的实现类,不过该类不是公开的,下面就具体看看该类的一个实现的(该类具体存在于System.dll程序集,命名空间为System,大家可以用反射工具Reflector去查看源码的):

复制代码

// 该类不是一个公开类 // 但是该类的实现应用了单例模式
internal sealed class SR
{ private static SR loader; internal SR()
{
} // 主要是因为该类不是公有,所以这个全部访问点也定义为私有的了 // 但是思想还是用到了单例模式的思想的
private static SR GetLoader()
{ if (loader == null)
{
SR sr = new SR();
Interlocked.CompareExchange(ref loader, sr, null);
} return loader;
} // 这个公有方法中调用了GetLoader方法的
public static object GetObject(string name)
{
SR loader = GetLoader(); if (loader == null)
{ return null;
} return loader.resources.GetObject(name, Culture);
}
}

复制代码

六、总结

到这里,设计模式的单例模式就介绍完了,希望通过本文章大家可以对单例模式有一个更深的理解,并且希望之前没接触过单例模式或觉得单例模式陌生的朋友看完之后会惊叹:原来如此!

一、引言

在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码),而工厂方法模式每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性。但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们要设计这样的系统时,工厂方法模式显然在这里不适用,然后抽象工厂模式却可以很好地解决一系列产品创建的问题,这是本专题所要介绍的内容。

二、抽象工厂详细介绍

这里首先以一个生活中抽象工厂的例子来实现一个抽象工厂,然后再给出抽象工厂的定义和UML图来帮助大家更好地掌握抽象工厂模式,同时大家在理解的时候,可以对照抽象工厂生活中例子的实现和它的定义来加深抽象工厂的UML图理解。

2.1 抽象工厂的具体实现

下面就以生活中 “绝味” 连锁店的例子来实现一个抽象工厂模式。例如,绝味鸭脖想在江西南昌和上海开分店,但是由于当地人的口味不一样,在南昌的所有绝味的东西会做的辣一点,而上海不喜欢吃辣的,所以上海的所有绝味的东西都不会做的像南昌的那样辣,然而这点不同导致南昌绝味工厂和上海的绝味工厂生成所有绝味的产品都不同,也就是某个具体工厂需要负责一系列产品(指的是绝味所有食物)的创建工作,下面就具体看看如何使用抽象工厂模式来实现这种情况。

复制代码

1 ///


2 /// 下面以绝味鸭脖连锁店为例子演示下抽象工厂模式 3 /// 因为每个地方的喜欢的口味不一样,有些地方喜欢辣点的,有些地方喜欢吃不辣点 4 /// 客户端调用 5 ///

6 class Client 7 {
8 static void Main(string[] args)
9 {
10 // 南昌工厂制作南昌的鸭脖和鸭架
11 AbstractFactory nanChangFactory = new NanChangFactory(); 12 YaBo nanChangYabo = nanChangFactory.CreateYaBo(); 13 nanChangYabo.Print();
14 YaJia nanChangYajia= nanChangFactory.CreateYaJia(); 15 nanChangYajia.Print();
16
17 // 上海工厂制作上海的鸭脖和鸭架
18 AbstractFactory shangHaiFactory = new ShangHaiFactory(); 19 shangHaiFactory.CreateYaBo().Print();
20 shangHaiFactory.CreateYaJia().Print();
21
22 Console.Read();
23 }
24 }
25
26 ///
27 /// 抽象工厂类,提供创建两个不同地方的鸭架和鸭脖的接口 28 ///

29 public abstract class AbstractFactory 30 {
31 // 抽象工厂提供创建一系列产品的接口,这里作为例子,只给出了绝味中鸭脖和鸭架的创建接口
32 public abstract YaBo CreateYaBo(); 33 public abstract YaJia CreateYaJia(); 34 }
35
36 ///
37 /// 南昌绝味工厂负责制作南昌的鸭脖和鸭架 38 ///

39 public class NanChangFactory : AbstractFactory 40 {
41 // 制作南昌鸭脖
42 public override YaBo CreateYaBo() 43 {
44 return new NanChangYaBo(); 45 }
46 // 制作南昌鸭架
47 public override YaJia CreateYaJia() 48 {
49 return new NanChangYaJia(); 50 }
51 }
52
53 ///
54 /// 上海绝味工厂负责制作上海的鸭脖和鸭架 55 ///

56 public class ShangHaiFactory : AbstractFactory 57 {
58 // 制作上海鸭脖
59 public override YaBo CreateYaBo() 60 {
61 return new ShangHaiYaBo(); 62 }
63 // 制作上海鸭架
64 public override YaJia CreateYaJia() 65 {
66 return new ShangHaiYaJia(); 67 }
68 }
69
70 ///
71 /// 鸭脖抽象类,供每个地方的鸭脖类继承 72 ///

73 public abstract class YaBo 74 {
75 ///
76 /// 打印方法,用于输出信息 77 ///

78 public abstract void Print(); 79 }
80
81 ///
82 /// 鸭架抽象类,供每个地方的鸭架类继承 83 ///

84 public abstract class YaJia 85 {
86 ///
87 /// 打印方法,用于输出信息 88 ///

89 public abstract void Print(); 90 }
91
92 ///
93 /// 南昌的鸭脖类,因为江西人喜欢吃辣的,所以南昌的鸭脖稍微会比上海做的辣 94 ///

95 public class NanChangYaBo : YaBo 96 {
97 public override void Print() 98 {
99 Console.WriteLine(“南昌的鸭脖”); 100 } 101 } 102
103 ///
104 /// 上海的鸭脖没有南昌的鸭脖做的辣 105 ///

106 public class ShangHaiYaBo : YaBo 107 { 108 public override void Print() 109 { 110 Console.WriteLine(“上海的鸭脖”); 111 } 112 } 113
114 ///
115 /// 南昌的鸭架 116 ///

117 public class NanChangYaJia : YaJia 118 { 119 public override void Print() 120 { 121 Console.WriteLine(“南昌的鸭架子”); 122 } 123 } 124
125 ///
126 /// 上海的鸭架 127 ///

128 public class ShangHaiYaJia : YaJia 129 { 130 public override void Print() 131 { 132 Console.WriteLine(“上海的鸭架子”); 133 } 134 }

复制代码

2.2 抽象工厂模式的定义和类图

上面代码中都有详细的注释,这里就不再解释上面的代码了,下面就具体看看抽象工厂模式的定义吧(理解定义可以参考上面的实现来加深理解):

抽象工厂模式:提供一个创建产品的接口来负责创建相关或依赖的对象,而不具体明确指定具体类

抽象工厂允许客户使用抽象的接口来创建一组相关产品,而不需要知道或关心实际生产出的具体产品是什么。这样客户就可以从具体产品中被解耦。下面通过抽象工模式的类图来了解各个类中之间的关系:

2.3 抽象工厂应对需求变更

看完上面抽象工厂的实现之后,如果 “绝味”公司又想在湖南开一家分店怎么办呢? 因为湖南人喜欢吃麻辣的,下面就具体看看应用了抽象工厂模式的系统是如何应对这种需求的。

复制代码

///


/// 如果绝味又想开一家湖南的分店时,因为湖南喜欢吃麻的 /// 所以这是有需要有一家湖南的工厂专门制作 ///

public class HuNanFactory : AbstractFactory
{ // 制作湖南鸭脖
public override YaBo CreateYaBo()
{ return new HuNanYaBo();
} // 制作湖南鸭架
public override YaJia CreateYaJia()
{ return new HuNanYajia();
}
} ///
/// 湖南的鸭脖 ///

public class HuNanYaBo : YaBo
{ public override void Print()
{
Console.WriteLine(“湖南的鸭脖”);
}
} ///
/// 湖南的鸭架 ///

public class HuNanYajia : YaJia
{ public override void Print()
{
Console.WriteLine(“湖南的鸭架子”);
}
}

复制代码

此时,只需要添加三个类:一个是湖南具体工厂类,负责创建湖南口味的鸭脖和鸭架,另外两个类是具有湖南口味的鸭脖类和鸭架类。从上面代码看出,抽象工厂对于系列产品的变化支持 “开放——封闭”原则(指的是要求系统对扩展开放,对修改封闭),扩展起来非常简便,但是,抽象工厂对于添加新产品这种情况就不支持”开放——封闭 “原则,这也是抽象工厂的缺点所在,这点会在第四部分详细介绍。

三、抽象工厂的分析

抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展,这真是抽象工厂模式的优点所在,然后抽象模式同时也存在不足的地方。下面就具体看下抽象工厂的缺点(缺点其实在前面的介绍中以已经涉及了):

抽象工厂模式很难支持新种类产品的变化。这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则。

知道了抽象工厂的优缺点之后,也就能很好地把握什么情况下考虑使用抽象工厂模式了,下面就具体看看使用抽象工厂模式的系统应该符合那几个前提:

  • 一个系统不要求依赖产品类实例如何被创建、组合和表达的表达,这点也是所有工厂模式应用的前提。
  • 这个系统有多个系列产品,而系统中只消费其中某一系列产品
  • 系统要求提供一个产品类的库,所有产品以同样的接口出现,客户端不需要依赖具体实现。

四、.NET中抽象工厂模式实现

抽象工厂模式在实际中的应用也是相当频繁的,然而在我们.NET类库中也存在应用抽象工厂模式的类,这个类就是System.Data.Common.DbProviderFactory,这个类位于System.Data.dll程序集中,该类扮演抽象工厂模式中抽象工厂的角色,我们可以用reflector反编译工具查看该类的实现:

复制代码

/// 扮演抽象工厂的角色
/// 创建连接数据库时所需要的对象集合,
/// 这个对象集合包括有 DbConnection对象(这个是抽象产品类,如绝味例子中的YaBo类)、DbCommand类、DbDataAdapter类,针对不同的具体工厂都需要实现该抽象类中方法,public abstract class DbProviderFactory
{ // 提供了创建具体产品的接口方法
protected DbProviderFactory(); public virtual DbCommand CreateCommand(); public virtual DbCommandBuilder CreateCommandBuilder(); public virtual DbConnection CreateConnection(); public virtual DbConnectionStringBuilder CreateConnectionStringBuilder(); public virtual DbDataAdapter CreateDataAdapter(); public virtual DbDataSourceEnumerator CreateDataSourceEnumerator(); public virtual DbParameter CreateParameter(); public virtual CodeAccessPermission CreatePermission(PermissionState state);
}

复制代码

DbProviderFactory类是一个抽象工厂类,该类提供了创建数据库连接时所需要的对象集合的接口,实际创建的工作在其子类工厂中进行,微软使用的是SQL Server数据库,因此提供了连接SQL Server数据的具体工厂实现,具体代码可以用反编译工具查看,具体代码如下:

复制代码

/// 扮演着具体工厂的角色,用来创建连接SQL Server数据所需要的对象
public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider
{ // Fields
public static readonly SqlClientFactory Instance = new SqlClientFactory(); // 构造函数
private SqlClientFactory()
{
} // 重写抽象工厂中的方法
public override DbCommand CreateCommand()
{ // 创建具体产品
return new SqlCommand();
} public override DbCommandBuilder CreateCommandBuilder()
{ return new SqlCommandBuilder();
} public override DbConnection CreateConnection()
{ return new SqlConnection();
} public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{ return new SqlConnectionStringBuilder();
} public override DbDataAdapter CreateDataAdapter()
{ return new SqlDataAdapter();
} public override DbDataSourceEnumerator CreateDataSourceEnumerator()
{ return SqlDataSourceEnumerator.Instance;
} public override DbParameter CreateParameter()
{ return new SqlParameter();
} public override CodeAccessPermission CreatePermission(PermissionState state)
{ return new SqlClientPermission(state);
}
}

复制代码

因为微软只给出了连接SQL Server的具体工厂的实现,我们也可以自定义连接Oracle、MySql的具体工厂的实现。

五、总结

到这里,抽象工厂模式的介绍就结束,在下一专题就将为大家介绍建造模式。

程序源码:抽象工厂模式实现