python 设计模式 23种_python实现23种设计模式

本文源码寄方于github:https://github.com/w392807287/Design_pattern_of_python

参考文献:

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

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

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

设计模式是什么?

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

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

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

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

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

创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。

结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。

行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

创建型

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 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Factory Method5 '''

6

7 classChinaGetter:8 """A simple localizer a la gettext"""

9 def __init__(self):10 self.trans = dict(dog=u"小狗", cat=u"小猫")11

12 defget(self, msgid):13 """We'll punt if we don't have a translation"""

14 try:15 returnself.trans[msgid]16 exceptKeyError:17 returnstr(msgid)18

19

20 classEnglishGetter:21 """Simply echoes the msg ids"""

22 defget(self, msgid):23 returnstr(msgid)24

25

26 def get_localizer(language="English"):27 """The factory method"""

28 languages = dict(English=EnglishGetter, China=ChinaGetter)29 returnlanguages[language]()30

31 #Create our localizers

32 e, g = get_localizer("English"), get_localizer("China")33 #Localize some text

34 for msgid in "dog parrot cat bear".split():35 print(e.get(msgid), g.get(msgid))

View Code

2. Abstract Factory(抽象工厂)

意图:

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

适用性:

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

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Abstract Factory5 '''

6

7 importrandom8

9 classPetShop:10 """A pet shop"""

11

12 def __init__(self, animal_factory=None):13 """pet_factory is our abstract factory.14 We can set it at will."""

15

16 self.pet_factory =animal_factory17

18 defshow_pet(self):19 """Creates and shows a pet using the20 abstract factory"""

21

22 pet =self.pet_factory.get_pet()23 print("This is a lovely", str(pet))24 print("It says", pet.speak())25 print("It eats", self.pet_factory.get_food())26

27

28 #Stuff that our factory makes

29

30 classDog:31 defspeak(self):32 return "woof"

33

34 def __str__(self):35 return "Dog"

36

37

38 classCat:39 defspeak(self):40 return "meow"

41

42 def __str__(self):43 return "Cat"

44

45

46 #Factory classes

47

48 classDogFactory:49 defget_pet(self):50 returnDog()51

52 defget_food(self):53 return "dog food"

54

55

56 classCatFactory:57 defget_pet(self):58 returnCat()59

60 defget_food(self):61 return "cat food"

62

63

64 #Create the proper family

65 defget_factory():66 """Let's be dynamic!"""

67 returnrandom.choice([DogFactory, CatFactory])()68

69

70 #Show pets with various factories

71 if __name__ == "__main__":72 shop =PetShop()73 for i in range(3):74 shop.pet_factory =get_factory()75 shop.show_pet()76 print("=" * 20)

View Code

3. Builder(建造者)

意图:

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

适用性:

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

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

1 #!/usr/bin/python

2 #coding:utf8

3

4 """

5 Builder6 """

7

8 #Director

9 classDirector(object):10 def __init__(self):11 self.builder =None12

13 defconstruct_building(self):14 self.builder.new_building()15 self.builder.build_floor()16 self.builder.build_size()17

18 defget_building(self):19 returnself.builder.building20

21

22 #Abstract Builder

23 classBuilder(object):24 def __init__(self):25 self.building =None26

27 defnew_building(self):28 self.building =Building()29

30

31 #Concrete Builder

32 classBuilderHouse(Builder):33 defbuild_floor(self):34 self.building.floor = 'One'

35

36 defbuild_size(self):37 self.building.size = 'Big'

38

39

40 classBuilderFlat(Builder):41 defbuild_floor(self):42 self.building.floor = 'More than One'

43

44 defbuild_size(self):45 self.building.size = 'Small'

46

47

48 #Product

49 classBuilding(object):50 def __init__(self):51 self.floor =None52 self.size =None53

54 def __repr__(self):55 return 'Floor: %s | Size: %s' %(self.floor, self.size)56

57

58 #Client

59 if __name__ == "__main__":60 director =Director()61 director.builder =BuilderHouse()62 director.construct_building()63 building =director.get_building()64 print(building)65 director.builder =BuilderFlat()66 director.construct_building()67 building =director.get_building()68 print(building)

View Code

4. Prototype(原型)

意图:

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

适用性:

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Prototype5 '''

6

7 importcopy8

9 classPrototype:10 def __init__(self):11 self._objects ={}12

13 defregister_object(self, name, obj):14 """Register an object"""

15 self._objects[name] =obj16

17 defunregister_object(self, name):18 """Unregister an object"""

19 delself._objects[name]20

21 def clone(self, name, **attr):22 """Clone a registered object and update inner attributes dictionary"""

23 obj =copy.deepcopy(self._objects.get(name))24 obj.__dict__.update(attr)25 returnobj26

27

28 defmain():29 classA:30 def __str__(self):31 return "I am A"

32

33 a =A()34 prototype =Prototype()35 prototype.register_object('a', a)36 b = prototype.clone('a', a=1, b=2, c=3)37

38 print(a)39 print(b.a, b.b, b.c)40

41

42 if __name__ == '__main__':43 main()

View Code

5. Singleton(单例)

意图:

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

适用性:

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

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

实现:

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Singleton5 '''

6

7 classSingleton(object):8 ''''' A python style singleton'''

9

10 def __new__(cls, *args, **kw):11 if not hasattr(cls, '_instance'):12 org =super(Singleton, cls)13 cls._instance = org.__new__(cls, *args, **kw)14 returncls._instance15

16

17 if __name__ == '__main__':18 classSingleSpam(Singleton):19 def __init__(self, s):20 self.s =s21

22 def __str__(self):23 returnself.s24

25

26 s1 = SingleSpam('spam')27 printid(s1), s128 s2 = SingleSpam('spa')29 printid(s2), s230 print id(s1), s1

View Code

结构型

6. Adapter Class/Object(适配器)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Adapter5 '''

6

7 importos8

9

10 classDog(object):11 def __init__(self):12 self.name = "Dog"

13

14 defbark(self):15 return "woof!"

16

17

18 classCat(object):19 def __init__(self):20 self.name = "Cat"

21

22 defmeow(self):23 return "meow!"

24

25

26 classHuman(object):27 def __init__(self):28 self.name = "Human"

29

30 defspeak(self):31 return "'hello'"

32

33

34 classCar(object):35 def __init__(self):36 self.name = "Car"

37

38 defmake_noise(self, octane_level):39 return "vroom%s" % ("!" *octane_level)40

41

42 classAdapter(object):43 """

44 Adapts an object by replacing methods.45 Usage:46 dog = Dog47 dog = Adapter(dog, dict(make_noise=dog.bark))48 """

49 def __init__(self, obj, adapted_methods):50 """We set the adapted methods in the object's dict"""

51 self.obj =obj52 self.__dict__.update(adapted_methods)53

54 def __getattr__(self, attr):55 """All non-adapted calls are passed to the object"""

56 returngetattr(self.obj, attr)57

58

59 defmain():60 objects =[]61 dog =Dog()62 objects.append(Adapter(dog, dict(make_noise=dog.bark)))63 cat =Cat()64 objects.append(Adapter(cat, dict(make_noise=cat.meow)))65 human =Human()66 objects.append(Adapter(human, dict(make_noise=human.speak)))67 car =Car()68 car_noise = lambda: car.make_noise(3)69 objects.append(Adapter(car, dict(make_noise=car_noise)))70

71 for obj inobjects:72 print "A", obj.name, "goes", obj.make_noise()73

74

75 if __name__ == "__main__":76 main()

View Code

7. Bridge(桥接)

意图:

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

适用性:

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

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

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

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Bridge5 '''

6

7

8 #ConcreteImplementor 1/2

9 classDrawingAPI1(object):10 defdraw_circle(self, x, y, radius):11 print('API1.circle at {}:{} radius {}'.format(x, y, radius))12

13

14 #ConcreteImplementor 2/2

15 classDrawingAPI2(object):16 defdraw_circle(self, x, y, radius):17 print('API2.circle at {}:{} radius {}'.format(x, y, radius))18

19

20 #Refined Abstraction

21 classCircleShape(object):22 def __init__(self, x, y, radius, drawing_api):23 self._x =x24 self._y =y25 self._radius =radius26 self._drawing_api =drawing_api27

28 #low-level i.e. Implementation specific

29 defdraw(self):30 self._drawing_api.draw_circle(self._x, self._y, self._radius)31

32 #high-level i.e. Abstraction specific

33 defscale(self, pct):34 self._radius *=pct35

36

37 defmain():38 shapes =(39 CircleShape(1, 2, 3, DrawingAPI1()),40 CircleShape(5, 7, 11, DrawingAPI2())41 )42

43 for shape inshapes:44 shape.scale(2.5)45 shape.draw()46

47

48 if __name__ == '__main__':49 main()

View Code

8. Composite(组合)

意图:

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

适用性:

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

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

1 #!/usr/bin/python

2 #coding:utf8

3

4 """

5 Composite6 """

7

8 classComponent:9 def __init__(self,strName):10 self.m_strName =strName11 defAdd(self,com):12 pass

13 defDisplay(self,nDepth):14 pass

15

16 classLeaf(Component):17 defAdd(self,com):18 print "leaf can't add"

19 defDisplay(self,nDepth):20 strtemp = "-" *nDepth21 strtemp=strtemp+self.m_strName22 printstrtemp23

24 classComposite(Component):25 def __init__(self,strName):26 self.m_strName =strName27 self.c =[]28 defAdd(self,com):29 self.c.append(com)30 defDisplay(self,nDepth):31 strtemp = "-"*nDepth32 strtemp=strtemp+self.m_strName33 printstrtemp34 for com inself.c:35 com.Display(nDepth+2)36

37 if __name__ == "__main__":38 p = Composite("Wong")39 p.Add(Leaf("Lee"))40 p.Add(Leaf("Zhao"))41 p1 = Composite("Wu")42 p1.Add(Leaf("San"))43 p.Add(p1)44 p.Display(1);

View Code

9. Decorator(装饰)

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Decorator5 '''

6

7 classfoo(object):8 deff1(self):9 print("original f1")10

11 deff2(self):12 print("original f2")13

14

15 classfoo_decorator(object):16 def __init__(self, decoratee):17 self._decoratee =decoratee18

19 deff1(self):20 print("decorated f1")21 self._decoratee.f1()22

23 def __getattr__(self, name):24 returngetattr(self._decoratee, name)25

26 u =foo()27 v =foo_decorator(u)28 v.f1()29 v.f2()

View Code

10. Facade(外观)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Decorator5 '''

6 importtime7

8 SLEEP = 0.5

9

10 #Complex Parts

11 classTC1:12 defrun(self):13 print("###### In Test 1 ######")14 time.sleep(SLEEP)15 print("Setting up")16 time.sleep(SLEEP)17 print("Running test")18 time.sleep(SLEEP)19 print("Tearing down")20 time.sleep(SLEEP)21 print("Test Finished\n")22

23

24 classTC2:25 defrun(self):26 print("###### In Test 2 ######")27 time.sleep(SLEEP)28 print("Setting up")29 time.sleep(SLEEP)30 print("Running test")31 time.sleep(SLEEP)32 print("Tearing down")33 time.sleep(SLEEP)34 print("Test Finished\n")35

36

37 classTC3:38 defrun(self):39 print("###### In Test 3 ######")40 time.sleep(SLEEP)41 print("Setting up")42 time.sleep(SLEEP)43 print("Running test")44 time.sleep(SLEEP)45 print("Tearing down")46 time.sleep(SLEEP)47 print("Test Finished\n")48

49

50 #Facade

51 classTestRunner:52 def __init__(self):53 self.tc1 =TC1()54 self.tc2 =TC2()55 self.tc3 =TC3()56 self.tests = [i for i in(self.tc1, self.tc2, self.tc3)]57

58 defrunAll(self):59 [i.run() for i inself.tests]60

61

62 #Client

63 if __name__ == '__main__':64 testrunner =TestRunner()65 testrunner.runAll()

View Code

11. Flyweight(享元)

意图:

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

适用性:

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

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

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Flyweight5 '''

6

7 importweakref8

9

10 classCard(object):11 """The object pool. Has builtin reference counting"""

12 _CardPool =weakref.WeakValueDictionary()13

14 """Flyweight implementation. If the object exists in the15 pool just return it (instead of creating a new one)"""

16 def __new__(cls, value, suit):17 obj = Card._CardPool.get(value +suit, None)18 if notobj:19 obj = object.__new__(cls)20 Card._CardPool[value + suit] =obj21 obj.value, obj.suit =value, suit22 returnobj23

24 #def __init__(self, value, suit):

25 #self.value, self.suit = value, suit

26

27 def __repr__(self):28 return "" %(self.value, self.suit)29

30

31 if __name__ == '__main__':32 #comment __new__ and uncomment __init__ to see the difference

33 c1 = Card('9', 'h')34 c2 = Card('9', 'h')35 print(c1, c2)36 print(c1 ==c2)37 print(id(c1), id(c2))

View Code

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 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Proxy5 '''

6

7 importtime8

9 classSalesManager:10 defwork(self):11 print("Sales Manager working...")12

13 deftalk(self):14 print("Sales Manager ready to talk")15

16 classProxy:17 def __init__(self):18 self.busy = 'No'

19 self.sales =None20

21 defwork(self):22 print("Proxy checking for Sales Manager availability")23 if self.busy == 'No':24 self.sales =SalesManager()25 time.sleep(2)26 self.sales.talk()27 else:28 time.sleep(2)29 print("Sales Manager is busy")30

31

32 if __name__ == '__main__':33 p =Proxy()34 p.work()35 p.busy = 'Yes'

36 p.work()

View Code

行为型

13. Interpreter(解释器)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Interpreter5 '''

6

7 classContext:8 def __init__(self):9 self.input=""

10 self.output=""

11

12 classAbstractExpression:13 defInterpret(self,context):14 pass

15

16 classExpression(AbstractExpression):17 defInterpret(self,context):18 print "terminal interpret"

19

20 classNonterminalExpression(AbstractExpression):21 defInterpret(self,context):22 print "Nonterminal interpret"

23

24 if __name__ == "__main__":25 context= ""

26 c =[]27 c = c +[Expression()]28 c = c +[NonterminalExpression()]29 c = c +[Expression()]30 c = c +[Expression()]31 for a inc:32 a.Interpret(context)

View Code

14. Template Method(模板方法)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Template Method5 '''

6

7 ingredients = "spam eggs apple"

8 line = '-' * 10

9

10 #Skeletons

11 defiter_elements(getter, action):12 """Template skeleton that iterates items"""

13 for element ingetter():14 action(element)15 print(line)16

17 defrev_elements(getter, action):18 """Template skeleton that iterates items in reverse order"""

19 for element in getter()[::-1]:20 action(element)21 print(line)22

23 #Getters

24 defget_list():25 returningredients.split()26

27 defget_lists():28 return [list(x) for x iningredients.split()]29

30 #Actions

31 defprint_item(item):32 print(item)33

34 defreverse_item(item):35 print(item[::-1])36

37 #Makes templates

38 defmake_template(skeleton, getter, action):39 """Instantiate a template method with getter and action"""

40 deftemplate():41 skeleton(getter, action)42 returntemplate43

44 #Create our template functions

45 templates =[make_template(s, g, a)46 for g in(get_list, get_lists)47 for a in(print_item, reverse_item)48 for s in(iter_elements, rev_elements)]49

50 #Execute them

51 for template intemplates:52 template()

View Code

15. Chain of Responsibility(责任链)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3

4 """

5 Chain6 """

7 classHandler:8 defsuccessor(self, successor):9 self.successor =successor10

11 classConcreteHandler1(Handler):12 defhandle(self, request):13 if request > 0 and request <= 10:14 print("in handler1")15 else:16 self.successor.handle(request)17

18 classConcreteHandler2(Handler):19 defhandle(self, request):20 if request > 10 and request <= 20:21 print("in handler2")22 else:23 self.successor.handle(request)24

25 classConcreteHandler3(Handler):26 defhandle(self, request):27 if request > 20 and request <= 30:28 print("in handler3")29 else:30 print('end of chain, no handler for {}'.format(request))31

32 classClient:33 def __init__(self):34 h1 =ConcreteHandler1()35 h2 =ConcreteHandler2()36 h3 =ConcreteHandler3()37

38 h1.successor(h2)39 h2.successor(h3)40

41 requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]42 for request inrequests:43 h1.handle(request)44

45 if __name__ == "__main__":46 client = Client()

View Code

16. Command(命令)

意图:

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

适用性:

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

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

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3

4 """

5 Command6 """

7 importos8

9 classMoveFileCommand(object):10 def __init__(self, src, dest):11 self.src =src12 self.dest =dest13

14 defexecute(self):15 self()16

17 def __call__(self):18 print('renaming {} to {}'.format(self.src, self.dest))19 os.rename(self.src, self.dest)20

21 defundo(self):22 print('renaming {} to {}'.format(self.dest, self.src))23 os.rename(self.dest, self.src)24

25

26 if __name__ == "__main__":27 command_stack =[]28

29 #commands are just pushed into the command stack

30 command_stack.append(MoveFileCommand('foo.txt', 'bar.txt'))31 command_stack.append(MoveFileCommand('bar.txt', 'baz.txt'))32

33 #they can be executed later on

34 for cmd incommand_stack:35 cmd.execute()36

37 #and can also be undone at will

38 for cmd inreversed(command_stack):39 cmd.undo()

View Code

17. Iterator(迭代器)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Interator5 '''

6 defcount_to(count):7 """Counts by word numbers, up to a maximum of five"""

8 numbers = ["one", "two", "three", "four", "five"]9 #enumerate() returns a tuple containing a count (from start which

10 #defaults to 0) and the values obtained from iterating over sequence

11 for pos, number inzip(range(count), numbers):12 yieldnumber13

14 #Test the generator

15 count_to_two = lambda: count_to(2)16 count_to_five = lambda: count_to(5)17

18 print('Counting to two...')19 for number incount_to_two():20 printnumber21

22 print " "

23

24 print('Counting to five...')25 for number incount_to_five():26 printnumber27

28 print " "

View Code

18. Mediator(中介者)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Mediator5 '''

6 """http://dpip.testingperspective.com/?p=28"""

7

8 importtime9

10 classTC:11 def __init__(self):12 self._tm =tm13 self._bProblem =014

15 defsetup(self):16 print("Setting up the Test")17 time.sleep(1)18 self._tm.prepareReporting()19

20 defexecute(self):21 if notself._bProblem:22 print("Executing the test")23 time.sleep(1)24 else:25 print("Problem in setup. Test not executed.")26

27 deftearDown(self):28 if notself._bProblem:29 print("Tearing down")30 time.sleep(1)31 self._tm.publishReport()32 else:33 print("Test not executed. No tear down required.")34

35 defsetTM(self, TM):36 self._tm =tm37

38 defsetProblem(self, value):39 self._bProblem =value40

41 classReporter:42 def __init__(self):43 self._tm =None44

45 defprepare(self):46 print("Reporter Class is preparing to report the results")47 time.sleep(1)48

49 defreport(self):50 print("Reporting the results of Test")51 time.sleep(1)52

53 defsetTM(self, TM):54 self._tm =tm55

56 classDB:57 def __init__(self):58 self._tm =None59

60 definsert(self):61 print("Inserting the execution begin status in the Database")62 time.sleep(1)63 #Following code is to simulate a communication from DB to TC

64 importrandom65 if random.randrange(1, 4) == 3:66 return -1

67

68 defupdate(self):69 print("Updating the test results in Database")70 time.sleep(1)71

72 defsetTM(self, TM):73 self._tm =tm74

75 classTestManager:76 def __init__(self):77 self._reporter =None78 self._db =None79 self._tc =None80

81 defprepareReporting(self):82 rvalue =self._db.insert()83 if rvalue == -1:84 self._tc.setProblem(1)85 self._reporter.prepare()86

87 defsetReporter(self, reporter):88 self._reporter =reporter89

90 defsetDB(self, db):91 self._db =db92

93 defpublishReport(self):94 self._db.update()95 rvalue =self._reporter.report()96

97 defsetTC(self, tc):98 self._tc =tc99

100

101 if __name__ == '__main__':102 reporter =Reporter()103 db =DB()104 tm =TestManager()105 tm.setReporter(reporter)106 tm.setDB(db)107 reporter.setTM(tm)108 db.setTM(tm)109 #For simplification we are looping on the same test.

110 #Practically, it could be about various unique test classes and their

111 #objects

112 while(True):113 tc =TC()114 tc.setTM(tm)115 tm.setTC(tc)116 tc.setup()117 tc.execute()118 tc.tearDown()

View Code

19. Memento(备忘录)

意图:

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

适用性:

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Memento5 '''

6

7 importcopy8

9 def Memento(obj, deep=False):10 state = (copy.copy, copy.deepcopy)[bool(deep)](obj.__dict__)11

12 defRestore():13 obj.__dict__.clear()14 obj.__dict__.update(state)15 returnRestore16

17 classTransaction:18 """A transaction guard. This is really just19 syntactic suggar arount a memento closure.20 """

21 deep =False22

23 def __init__(self, *targets):24 self.targets =targets25 self.Commit()26

27 defCommit(self):28 self.states = [Memento(target, self.deep) for target inself.targets]29

30 defRollback(self):31 for st inself.states:32 st()33

34 classtransactional(object):35 """Adds transactional semantics to methods. Methods decorated with36 @transactional will rollback to entry state upon exceptions.37 """

38 def __init__(self, method):39 self.method =method40

41 def __get__(self, obj, T):42 def transaction(*args, **kwargs):43 state =Memento(obj)44 try:45 return self.method(obj, *args, **kwargs)46 except:47 state()48 raise

49 returntransaction50

51 classNumObj(object):52 def __init__(self, value):53 self.value =value54

55 def __repr__(self):56 return '' % (self.__class__.__name__, self.value)57

58 defIncrement(self):59 self.value += 1

60

61 @transactional62 defDoStuff(self):63 self.value = '1111' #

64 self.Increment() #

65

66 if __name__ == '__main__':67 n = NumObj(-1)68 print(n)69 t =Transaction(n)70 try:71 for i in range(3):72 n.Increment()73 print(n)74 t.Commit()75 print('-- commited')76 for i in range(3):77 n.Increment()78 print(n)79 n.value += 'x' #will fail

80 print(n)81 except:82 t.Rollback()83 print('-- rolled back')84 print(n)85 print('-- now doing stuff ...')86 try:87 n.DoStuff()88 except:89 print('-> doing stuff failed!')90 importtraceback91 traceback.print_exc(0)92 pass

93 print(n)

View Code

20. Observer(观察者)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Observer5 '''

6

7

8 classSubject(object):9 def __init__(self):10 self._observers =[]11

12 defattach(self, observer):13 if not observer inself._observers:14 self._observers.append(observer)15

16 defdetach(self, observer):17 try:18 self._observers.remove(observer)19 exceptValueError:20 pass

21

22 def notify(self, modifier=None):23 for observer inself._observers:24 if modifier !=observer:25 observer.update(self)26

27 #Example usage

28 classData(Subject):29 def __init__(self, name=''):30 Subject.__init__(self)31 self.name =name32 self._data =033

34 @property35 defdata(self):36 returnself._data37

38 @data.setter39 defdata(self, value):40 self._data =value41 self.notify()42

43 classHexViewer:44 defupdate(self, subject):45 print('HexViewer: Subject %s has data 0x%x' %

46 (subject.name, subject.data))47

48 classDecimalViewer:49 defupdate(self, subject):50 print('DecimalViewer: Subject %s has data %d' %

51 (subject.name, subject.data))52

53 #Example usage...

54 defmain():55 data1 = Data('Data 1')56 data2 = Data('Data 2')57 view1 =DecimalViewer()58 view2 =HexViewer()59 data1.attach(view1)60 data1.attach(view2)61 data2.attach(view2)62 data2.attach(view1)63

64 print("Setting Data 1 = 10")65 data1.data = 10

66 print("Setting Data 2 = 15")67 data2.data = 15

68 print("Setting Data 1 = 3")69 data1.data = 3

70 print("Setting Data 2 = 5")71 data2.data = 5

72 print("Detach HexViewer from data1 and data2.")73 data1.detach(view2)74 data2.detach(view2)75 print("Setting Data 1 = 10")76 data1.data = 10

77 print("Setting Data 2 = 15")78 data2.data = 15

79

80 if __name__ == '__main__':81 main()

View Code

21. State(状态)

意图:

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

适用性:

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 State5 '''

6

7 classState(object):8 """Base state. This is to share functionality"""

9

10 defscan(self):11 """Scan the dial to the next station"""

12 self.pos += 1

13 if self.pos ==len(self.stations):14 self.pos =015 print("Scanning... Station is", self.stations[self.pos], self.name)16

17

18 classAmState(State):19 def __init__(self, radio):20 self.radio =radio21 self.stations = ["1250", "1380", "1510"]22 self.pos =023 self.name = "AM"

24

25 deftoggle_amfm(self):26 print("Switching to FM")27 self.radio.state =self.radio.fmstate28

29 classFmState(State):30 def __init__(self, radio):31 self.radio =radio32 self.stations = ["81.3", "89.1", "103.9"]33 self.pos =034 self.name = "FM"

35

36 deftoggle_amfm(self):37 print("Switching to AM")38 self.radio.state =self.radio.amstate39

40 classRadio(object):41 """A radio. It has a scan button, and an AM/FM toggle switch."""

42 def __init__(self):43 """We have an AM state and an FM state"""

44 self.amstate =AmState(self)45 self.fmstate =FmState(self)46 self.state =self.amstate47

48 deftoggle_amfm(self):49 self.state.toggle_amfm()50

51 defscan(self):52 self.state.scan()53

54 #Test our radio out

55 if __name__ == '__main__':56 radio =Radio()57 actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2

58 actions = actions * 2

59

60 for action inactions:61 action()

View Code

22. Strategy(策略)

意图:

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

适用性:

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

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 """

4 Strategy5 In most of other languages Strategy pattern is implemented via creating some base strategy interface/abstract class and6 subclassing it with a number of concrete strategies (as we can see at http://en.wikipedia.org/wiki/Strategy_pattern),7 however Python supports higher-order functions and allows us to have only one class and inject functions into it's8 instances, as shown in this example.9 """

10 importtypes11

12

13 classStrategyExample:14 def __init__(self, func=None):15 self.name = 'Strategy Example 0'

16 if func is notNone:17 self.execute =types.MethodType(func, self)18

19 defexecute(self):20 print(self.name)21

22 defexecute_replacement1(self):23 print(self.name + 'from execute 1')24

25 defexecute_replacement2(self):26 print(self.name + 'from execute 2')27

28 if __name__ == '__main__':29 strat0 =StrategyExample()30

31 strat1 =StrategyExample(execute_replacement1)32 strat1.name = 'Strategy Example 1'

33

34 strat2 =StrategyExample(execute_replacement2)35 strat2.name = 'Strategy Example 2'

36

37 strat0.execute()38 strat1.execute()39 strat2.execute()

View Code

23. Visitor(访问者)

意图:

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

适用性:

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

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

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

1 #!/usr/bin/python

2 #coding:utf8

3 '''

4 Visitor5 '''

6 classNode(object):7 pass

8

9 classA(Node):10 pass

11

12 classB(Node):13 pass

14

15 classC(A, B):16 pass

17

18 classVisitor(object):19 def visit(self, node, *args, **kwargs):20 meth =None21 for cls in node.__class__.__mro__:22 meth_name = 'visit_'+cls.__name__

23 meth =getattr(self, meth_name, None)24 ifmeth:25 break

26

27 if notmeth:28 meth =self.generic_visit29 return meth(node, *args, **kwargs)30

31 def generic_visit(self, node, *args, **kwargs):32 print('generic_visit'+node.__class__.__name__)33

34 def visit_B(self, node, *args, **kwargs):35 print('visit_B'+node.__class__.__name__)36

37 a =A()38 b =B()39 c =C()40 visitor =Visitor()41 visitor.visit(a)42 visitor.visit(b)43 visitor.visit(c)

View Code

你可能感兴趣的:(python,设计模式,23种)