设计模式笔记
# 设计模式笔记
# 链接资料
Refactoring
# 简介
设计模式是对软件设计中普遍存在或反复出向的各种问题所提出的解决方案。每一个设计模式系统地被命名、解释和评价了面向对象系统中一个重要和重复出现的设计。
设计模式的分类:
- 创建型模式:工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式。
隐藏底层模块的逻辑,关注怎么创建对象
。 - 结构型模式:适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
类之间如何协同工作,应该组成什么结构
。 - 行为型模式:解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模板方法模式。
关注行为,也就是方法,应该怎样某些行为
。
面向对象
设计模式解决的就是面向对象中的问题。需要指导面向对象的三大特性是 封装、继承和多态
,封装是把数据和方法封装到类中,继承是类之间复用代码,多态在Python中默认支持的,Python是一种多态的语言。
接口
接口是若干抽象方法的集合
。接口的作用是限制实现接口的类必须按照接口给定的调用方式实现这些方法,对高层模块隐藏了类的内部实现。下面通过一个简单的例子来加强对接口的理解:
from abc import ABCMeta, abstractmethod
# 具有抽象方法的类就是接口类,
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
"""
抽象方法,在实现的类中必须实现的方法。限制实现接口的类必须按照接口给定的调用方式实现这些方法
:param money:
:return:
"""
pass
# 不能说是继承接口类,应该说是实现接口
class Alipay(Payment):
def pay(self, money):
"""
实现接口类中的必须实现的方法
:param money:
:return:
"""
print("支付宝支付了{0}元!".format(money))
class WechatPay(Payment):
def pay(self, money):
"""
实现接口类中的必须实现的方法
:param money:
:return:
"""
print("微信支付了%d元!" % (money))
# 下面是高层代码,在调用的时候是看不到底层类的内部实现
a = Alipay()
w = WechatPay()
a.pay(100)
w.pay(100)
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
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
# 创建模式
# 1. 简单工厂模式
说明:
不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责产品的实例。
角色:
工厂角色(Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
1
2
3
4
5
6
2
3
4
5
6
优点
- 隐藏了对象创建的实现细节
- 客户端不需要修改代码
缺点
- 违反了单一职责原则,将创建逻辑集中到一个工厂类中
- 当添加新产品时,修改工厂类代码,违反了开闭原则
具体实现
"""
不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责产品的实例。
"""
from abc import abstractmethod, ABCMeta
# 抽象产品角色(Product)
class Payment(metaclass=ABCMeta):
@abstractmethod # 抽象类,表示如果有子类继承这个父类,那么这个方法就必须要实现
def pay(self, money):
pass
# 具体产品角色(Concrete Product)
class Alipay(Payment):
"""支付宝支付"""
def __init__(self, huabei=False):
self.huabei = huabei # huabei=True,表示使用花呗付款
def pay(self, money):
if self.huabei:
print("花呗支付%d" % money)
else:
print("支付宝支付%d" % money)
# 具体产品角色(Concrete Product)
class WechatPay(Payment):
"""微信支付"""
def pay(self, money):
print("微信支付%d" % money)
# 工厂角色(Creator)
class PaymentFactory:
"""创建工厂类,不暴露微信支付宝支付的方法,只用输入alipay,wechat,huabei,就可以调用相应的方法.这样外部就不知道我们内部是怎么样实现的"""
def create_payment(self, method):
if method == "alipay":
return Alipay()
elif method == 'wechat':
return WechatPay()
elif method == "huabei":
return Alipay(huabei=True)
else:
raise TypeError("No such payment named(没有这种支付方式:) %s" % method)
pf = PaymentFactory()
# 外部调用只用知道alipay,wechat,huabei,不会知道我们内部是怎么样实现的
a = pf.create_payment("huabei")
a.pay(500)
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
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
# 2. 工厂方法模式
说明
定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
就是在简单工厂模型下,定义抽象工厂,让每个子类决定去实现那个产品
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
优点
- 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
- 隐藏了对象创建的实现细节
缺点
- 每增加一个具体产品类,就必须增加一个相应的具体工厂类
具体实现
"""
定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类
"""
from abc import abstractmethod, ABCMeta
# 抽象产品角色(Product)
class Payment(metaclass=ABCMeta):
@abstractmethod # 抽象类,表示如果有子类继承这个父类,那么这个方法就必须要实现
def pay(self, money):
pass
# 具体产品角色(Concrete Product)
class Alipay(Payment):
"""支付宝支付"""
def __init__(self, huabei=False):
self.huabei = huabei # huabei=True,表示使用花呗付款
def pay(self, money):
if self.huabei:
print("花呗支付%d" % money)
else:
print("支付宝支付%d" % money)
# 具体产品角色(Concrete Product)
class WechatPay(Payment):
"""微信支付"""
def pay(self, money):
print("微信支付%d" % money)
# 抽象工厂角色(Creator)
class PaymentFactory(metaclass=ABCMeta):
"""创建工厂类,不暴露微信支付宝支付的方法,只用输入alipay,wechat,huabei,就可以调用相应的方法.这样外部就不知道我们内部是怎么样实现的"""
@abstractmethod
def create_payment(self):
pass
# 具体工厂角色(Concrete Creator)
class AlipayFactory(PaymentFactory):
def create_payment(self):
return Alipay()
class WechatFactory(PaymentFactory):
def create_payment(self):
return WechatPay()
class HuabeiFactory(PaymentFactory):
def create_payment(self):
return Alipay(huabei=True)
# 把一个工厂类通过,抽象工厂的方式,拆分成多个具体的工厂类。(让用户调用的时候看不到我们处理代码的逻辑)
pf = HuabeiFactory()
# 外部调用只用知道alipay,wechat,huabei,不会知道我们内部是怎么样实现的
a = pf.create_payment()
a.pay(500)
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
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
# 3. 抽象工厂模式
说明
内容:定义一个工厂类接口,让工厂子类来创建一系类相关或相互依赖的对象。
例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
客户端(Client)
其实就是:
1、先创建抽象产品(手机壳、cpu、操作系统)
2、创建抽象产品具体的产品(比如,苹果手机壳,华为手机壳)
3、创建抽象工厂,手机加工需要(手机壳、cpu、操作系统)
4、创建具体工厂,添加对应的手机配置
5、创建客户端,传递具体工厂来实现手机的组装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
优点
- 将客户端与类的具体实现分离
- 每个工厂创建了一个完整的产品系列,使得易于交换产品系列
- 有利于产品的一致性(即产品之间的约束关系)
缺点
- 难以支持新种类的(抽象)产品,因为一旦添加新产品就需要大改。
具体实现
"""
内容:定义一个工厂类接口,让工厂子类来创建一系类相关或相互依赖的对象。
例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
客户端(Client)
其实就是:
1、先创建抽象产品(手机壳、cpu、操作系统)
2、创建抽象产品具体的产品(比如,苹果手机壳,华为手机壳)
3、创建抽象工厂,手机加工需要(手机壳、cpu、操作系统)
4、创建具体工厂,添加对应的手机配置
5、创建客户端,传递具体工厂来实现手机的组装
"""
from abc import ABCMeta, abstractmethod
# ------抽象产品------
class PhoneShell(metaclass=ABCMeta):
"""手机壳"""
@abstractmethod
def show_shell(self):
pass
class CPU(metaclass=ABCMeta):
"""CPU"""
@abstractmethod
def show_cpu(self):
pass
class OS(metaclass=ABCMeta):
"""系统"""
@abstractmethod
def show_os(self):
pass
# ------抽象工厂------
class PhoneFactory(metaclass=ABCMeta):
"""手机加工"""
@abstractmethod
def make_shell(self): # 手机壳
pass
@abstractmethod
def make_cpu(self): # cpu
pass
@abstractmethod
def make_os(self): # 系统
pass
# ------具体产品------
class SmallShell(PhoneShell):
def show_shell(self):
print("普通手机小手机壳")
class AppleShell(PhoneShell):
def show_shell(self):
print("苹果手机壳")
class SnapDragonCPU(CPU):
def show_cpu(self):
print("骁龙CPU")
class AppleCPU(CPU):
def show_cpu(self):
print("苹果CPU")
class Android(OS):
def show_os(self):
print("Android系统")
class IOS(OS):
def show_os(self):
print("iOS系统")
# ------具体工厂------
class HuaweiFactory(PhoneFactory):
def make_cpu(self):
return SnapDragonCPU()
def make_os(self):
return Android()
def make_shell(self):
return SmallShell()
class IPhoneFactory(PhoneFactory):
def make_cpu(self):
return AppleCPU()
def make_os(self):
return IOS()
def make_shell(self):
return AppleShell()
# ------客户端------
class Phone:
def __init__(self, cpu, os, shell):
self.cpu = cpu
self.os = os
self.shell = shell
def show_info(self):
print("手机信息:")
self.cpu.show_cpu()
self.os.show_os()
self.shell.show_shell()
def make_phone(factory):
cpu = factory.make_cpu()
os = factory.make_os()
shell = factory.make_shell()
return Phone(cpu, os, shell)
p1 = make_phone(HuaweiFactory())
p1.show_info()
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
119
120
121
122
123
124
125
126
127
128
129
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
119
120
121
122
123
124
125
126
127
128
129
# 4. 建造者模式
说明
将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示。
和工厂模式不一样,工厂模式是直接返回一个产品(或工厂),输入输出,相当直接,建造者模式就要辛苦一点,需要指挥者指挥建造者工作之后,才能获得产品,所以建造者模式需要指挥者和建造者两个角色
角色:
抽象建造者(Builder)
具体建造者(Concrete Builder)
指挥者(Director)
产品(Product)
其实就是:
0、创建一个产品信息
1、创建一个抽象的建造者,里面有脸-身体-手-腿
2、实现具体建造者,把对应的参数给产品信息(通过init得到产品对象,把具体的信息直接给产品对象)
3、创建指挥者,控制角色组装顺序,并返回具体建造者对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 建造者模式与抽象工厂模式相似,也用来创建复杂对象。注意区别是建造者模式着重一步步构造一个复杂对象,并控制先后顺序。而抽象工厂着重于多个系列的产品对象。
优点:
- 隐藏了一个产品的内部结构和装配过程
- 将构造代码与表示代码分开
- 可以对构造过程进行更精细的控制
具体实现
"""
将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示。
和工厂模式不一样,工厂模式是直接返回一个产品(或工厂),输入输出,相当直接,建造者模式就要辛苦一点,需要指挥者指挥建造者工作之后,才能获得产品,所以建造者模式需要指挥者和建造者两个角色
角色:
抽象建造者(Builder)
具体建造者(Concrete Builder)
指挥者(Director)
产品(Product)
其实就是:
0、创建一个产品信息
1、创建一个抽象的建造者,里面有脸-身体-手-腿
2、实现具体建造者,把对应的参数给产品信息(通过init得到产品对象,把具体的信息直接给产品对象)
3、创建指挥者,控制角色组装顺序,并返回具体建造者对象
"""
from abc import abstractmethod, ABCMeta
class Player:
"""产品信息"""
def __init__(self, face=None, body=None, arm=None, leg=None):
self.face = face
self.body = body
self.arm = arm
self.leg = leg
def __str__(self):
return "游戏角色信息:{} -- {} -- {} -- {}".format(self.face, self.body, self.arm, self.leg)
class PlayerBuilder(metaclass=ABCMeta):
"""抽象建造者,脸-身体-手-腿"""
@abstractmethod
def build_face(self):
pass
@abstractmethod
def build_body(self):
pass
@abstractmethod
def build_arm(self):
pass
@abstractmethod
def build_leg(self):
pass
class ConcreteBuilder(PlayerBuilder):
"""具体建造者"""
def __init__(self):
self.player = Player() # 把得到的信息,给产品详细
def build_face(self):
self.player.face = "人脸"
def build_body(self):
self.player.body = "猪身体"
def build_arm(self):
self.player.arm = "大白手"
def build_leg(self):
self.player.leg = "细腿"
class PlayerDirector:
"""指挥者,控制组装顺序"""
def build_player(self, builder):
builder.build_body()
builder.build_face()
builder.build_arm()
builder.build_leg()
return builder.player
builder = ConcreteBuilder() # 具体建造者
director = PlayerDirector() # 指挥者
p = director.build_player(builder)
print(p)
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
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
# 5. 单例模式
说明
保证一个类只有一个实例,并提供一个访问它的全局访问点
角色:
单例(Singleton)
1
2
3
4
2
3
4
优点:
- 对唯一实例的受控访问
- 单例相当于全局变量,但防止了命名空间被污染
具体实现
"""
保证一个类只有一个实例,并提供一个访问它的全局访问点
角色:
单例(Singleton)
"""
class Singleton:
"""单例模式"""
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"): # hasattr() 函数用于判断对象是否包含对应的属性。
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
class Test(Singleton):
def __init__(self, a):
self.a = a
test = Test(10)
test1 = Test(20)
print(test.a)
print(test1.a) # 无论创建多少个对象,都指向一个实例对象
print(id(test), id(test1))
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
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
# 创建型模式小结
- 抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂。
- 通常情况下、设计以简单工厂模式或工厂方法模式开始,当你发现设计需要更大的灵活性时,则向更复杂的设计模式演化。
# 结构型模式
# 1. 适配器模式
说明
将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
角色:
目标接口(Target)
待适配的类(Adaptee)
适配器(Adapter)
在软件设计中,为了解决接口不一致的问题,两个软件模块之间往往需要通过一个适配器类 Adapter 进行“适配”。这样的模式叫做适配器设计模式。该模式可以分为两种,分别为类适配器模式(Class Adapter Pattern)和对象适配器模式(Object Adapter Pattern)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
两种实现方式:
- 类适配器:使用多继承
- 对象适配器:使用组合
适用场景:
- 想使用一个已经存在的类,而它的接口不符合你的要求
- (对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类以匹配它们的接口。对象适配器可以适配它的父类接口。
实现适配器的两种方式,类适配器使用多继承,对象适配器使用组合
。组合就是一个类中放入另一类的对象。
先来看下组合:
class A:
pass
class B:
def __init__():
self.a = A()
1
2
3
4
5
6
2
3
4
5
6
具体实现
# 抽象产品角色(Product)
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta): # 目标接口(Target)
@abstractmethod
def pay(self, money):
pass
class WechatPay(Payment):
"""微信支付"""
def pay(self, money):
print("微信支付%d" % money)
class Alipay: # 待适配的类(Adaptee)
"""支付宝支付"""
def cost(self, money):
print("支付宝支付%d" % money)
# 类适配器(Adapter)
class NewAlipay(Payment, Alipay):
"""类适配器:使用多继承"""
def pay(self, money):
self.cost(money)
new_alipay = NewAlipay() # 在类适配器中调用这个适配的方法
new_alipay.pay(100)
new_alipay = WechatPay()
new_alipay.pay(100)
"""
支付宝支付100
微信支付100
"""
# 对象适配器
class PaymentAdapter(Payment):
def __init__(self, payment):
self.payment = payment # 对象组合方式
def pay(self, money):
"""可以使用判断,适配多个方法"""
try:
self.payment.cost(money)
except:
self.payment.pay(money)
payment_adapter = PaymentAdapter(Alipay())
payment_adapter.pay(100)
"""
支付宝支付100
"""
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
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
# 2. 桥模式
说明
将一个事物的两个维度分离,使其可以独立地变化。
角色:
抽象(Abstraction)
细化抽象(RefinedAbstraction)
实现者(Implementor)
具体实现者(Concretelmplementor)
可将业务逻辑或一个大类拆分为不同的层次结构 , 从而能独立地进行开发 。 层次结构中的第一层 ( 通常称为抽象部分 ) 将包含对第二层 ( 实现部分 ) 对象的引用 。
桥模式是将一个事物的两个维度分离,使其都可以独立地变化。当事物有两个维度的表现,两个维度都可能扩展时使用。优点是:抽象和实现相分离,扩展能力强。如果不使用桥模式,在任何维度进行扩展,需要改好多代码,因为使用到了继承:
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
应用场景:
- 当事物有两个维度上的表现,两个维度都可能扩展时。
优点:
- 抽象和实现相分离
- 优秀的扩展能力
具体实现
"""
将一个事物的两个维度分离,使其可以独立地变化。
角色:
抽象(Abstraction)
细化抽象(RefinedAbstraction)
实现者(Implementor)
具体实现着(Concretelmplementor)
可将业务逻辑或一个大类拆分为不同的层次结构 , 从而能独立地进行开发 。 层次结构中的第一层 ( 通常称为抽象部分 ) 将包含对第二层 ( 实现部分 ) 对象的引用 。
其实就是:
1、把有"颜色的形状"拆分成二层,第一层:形状,第二层:颜色。通过形状(主)去实现颜色(辅)
2、创建形状和颜色的抽象类,在形状的init中得到颜色对象,通过形状去形状颜色
以上代码形状和颜色两个维度是通过类的继承关系紧密结合在一起,是紧耦合。紧耦合是是不可取的,应用桥模式的思想,
可以使用组合来实现(松耦合)。如果需要画直线,直接加上直线的类。需要新颜色,直接加上颜色的类。两个维度都可以自由扩展,
不需要添加很多代码。这里的角色有抽象、细化抽象、实现者和具体实现者:
"""
from abc import ABCMeta, abstractmethod
class Shape(metaclass=ABCMeta): # 抽象(Abstraction)
"""形状"""
def __init__(self, color):
self.color = color
@abstractmethod
def draw(self):
"""形状"""
pass
class Color(metaclass=ABCMeta): # 细化抽象(RefinedAbstraction)
"""颜色"""
@abstractmethod
def paint(self, shape):
pass
class Rectangle(Shape):
"""长方形"""
name = "长方形"
def draw(self):
self.color.paint(self)
class Red(Color):
def paint(self, shape):
print("红色的", shape.name)
class Green(Color):
def paint(self, shape):
print("绿色的", shape.name)
rectangle = Rectangle(Green())
rectangle.draw()
rectangle = Rectangle(Red())
rectangle.draw()
"""
绿色的 长方形
红色的 长方形
"""
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
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
# 3. 组合模式
说明
将对象组合成树形结构以表示“部分-整体”的层次结构(特别是结构是递归的),组合模式使得用户对单个对象和组合对象的使用具有一致性。
角色:
抽象组件(Component)
叶子组件(Leaf)
复合组件(Composite)
客户端(Client)
1
2
3
4
5
6
7
2
3
4
5
6
7
适用场景:
- 表示对象的“部分-整体”层次结构(特别是结构是递归的)
- 希望用户忽略组合对象与单个对象的不同,用户统一地适用组合结构中的所有对象
优点:
- 优点是定义了包含基本对象和组合对象的层次结构。
- 简化客户端代码,客户端可以一致地使用组合对象和单个对象。
- 更加容易增加新类型的组件。
具体实现
"""
将对象组合成树形结构以表示“部分-整体”的层次结构(特别是结构是递归的),组合模式使得用户对单个对象和组合对象的使用具有一致性。
角色:
抽象组件(Component)
叶子组件(Leaf)
复合组件(Composite)
客户端(Client)
其实就是:
1、把部分组合成一个整体,就像一个线段包含二个点
"""
from abc import ABCMeta, abstractmethod
# 抽象组件(Component)
class Graphic(metaclass=ABCMeta):
@abstractmethod
def draw(self):
pass
# 叶子组件(Leaf)
class Point(Graphic):
"""点"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "点(%d,%d)" % (self.x, self.y)
def draw(self):
print(str(self))
# 叶子组件(Leaf)
class Line(Graphic):
"""线"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return '线段[(%s,%s)]' % (self.x, self.y)
def draw(self):
print(str(self))
# 复合组件(Composite)
class Composite(Graphic):
def __init__(self, iterable):
self.children = []
for g in iterable: # 放入列表中
self.add(g)
def add(self, graphic):
self.children.append(graphic)
def draw(self):
for g in self.children: #
g.draw()
# 简单图形
print('------简单图形------')
p = Point(1, 2)
print(p)
l1 = Line(Point(1, 2), Point(3, 4)) # 一个线段包含二个点
l2 = Line(Point(5, 6), Point(7, 8))
print(l1, l2)
print('------复合图形(p,l1,l2)------')
# 复合图形
pic = Composite([p, l1, l2]) # 一个复合图形包含一个点,二个线段
pic.draw()
"""
------简单图形------
点(1,2)
线段[(点(1,2),点(3,4))] 线段[(点(5,6),点(7,8))]
------复合图形(p,l1,l2)------
点(1,2)
线段[(点(1,2),点(3,4))]
线段[(点(5,6),点(7,8))]
"""
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
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
# 4. 外观模式
在子系统类中调用一系列的外观
1
说明
外观模式为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。外观模式下的角色有外观和子系统类,优点是:减少系统相互依赖,提高灵活性,提高了安全性。下面看一个例子:
角色:
外观(facade)
子系统类(subsystem classes)
1
2
3
4
5
2
3
4
5
具体实现
"""
外观模式为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。外观模式下的角色有外观和子系统类,
优点是:减少系统相互依赖,提高灵活性,提高了安全性。
角色:
外观(facade)
子系统类(subsystem classes)
其实就是:
通过统一的类去实现某些方法,让外部看不到我们内部实现了什么方法
"""
# 外观(facade)
class CPU:
def run(self):
print("cpu开始运行")
def stop(self):
print("cpu停止")
# 外观(facade)
class Dist:
def run(self):
print("Disk开始运行")
def stop(self):
print("Disk停止")
# 外观(facade)
class Memory:
def run(self):
print("Memory开始运行")
def stop(self):
print("Memory停止")
# 子系统类(subsystem classes)
class Computer:
def __init__(self, cpu, dist, memory):
self.cpu = cpu
self.dist = dist
self.memory = memory
def run(self):
self.cpu.run() # 在子系统类中调用一系列的外观
self.dist.run()
self.memory.run()
def stop(self):
self.cpu.stop()
self.dist.stop()
self.memory.stop()
computer = Computer(CPU(), Dist(), Memory())
computer.run()
computer.stop()
"""
cpu开始运行
Disk开始运行
Memory开始运行
cpu停止
Disk停止
Memory停止
"""
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
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
# 5. 代理模式
通过代理对原有的实体类进一步操作
1
说明
为其它对象提供一种代理以控制对这个对象的访问。角色有抽象实体、实体和代理。应用场景有;下面是不使用虚代理的例子:
角色:
抽象实体(Subject)
实体(RealSubject)
代理(Proxy)
1
2
3
4
5
6
2
3
4
5
6
应用场景:
- 远程代理:为远程的对象提供代理(通过ORM向数据库写值,不用关注数据库是在远程)。
- 虚代理:根据需要创建很大的对象(需要的时候创建对象)。
- 保护代理:控制对原始对象的访问,用于对象有不同的访问权限。
优点:
- 远程代理:可以隐藏对象位于远程地址空间的事实
- 虚代理:可以进行优化,例如根据要求创建对象
- 保护代理:允许在访问一个对象时有一些附加的内务处理
不使用虚代理,只要是实例化 RealSubject 类,就会读取这个文件占用内存。使用虚代理后,可以和根据需要创建对象,用户不调用是不会创建 RealSubject 对象的,节省了内存的开销
具体实现
# 不实现虚代理
from abc import ABCMeta, abstractmethod
# 抽象实体(Subject)
class Subject(metaclass=ABCMeta):
"""读取文件写入文件"""
@abstractmethod
def get_content(self):
pass
@abstractmethod
def set_content(self, content):
pass
class RealSubject(Subject):
def __init__(self, filename):
self.filename = filename
print("读取文件内容!")
with open(self.filename, "r", encoding="UTF-8") as f:
self.centent = f.read()
def get_content(self):
return self.centent
def set_content(self, content):
print("写入文件内容!")
with open(self.filename, "w", encoding="UTF-8") as f:
f.write(content)
rs = RealSubject("test.txt")
rs.set_content("1111")
# rs.get_content()
"""
虚代理
"""
from abc import ABCMeta, abstractmethod
# 抽象实体(Subject)
class Subject(metaclass=ABCMeta):
"""读取文件写入文件"""
@abstractmethod
def get_content(self):
pass
@abstractmethod
def set_content(self, content):
pass
# 实体(RealSubject)
class RealSubject(Subject):
def __init__(self, filename):
self.filename = filename
print("读取文件内容!")
with open(self.filename, "r", encoding="UTF-8") as f:
self.centent = f.read()
def get_content(self):
return self.centent
def set_content(self, content):
print("写入文件内容!")
with open(self.filename, "w", encoding="UTF-8") as f:
f.write(content)
# 代理(Proxy)
class VirtualProxy(Subject):
def __init__(self, filename):
self.filename = filename
self.sub = None
def get_content(self):
if not self.sub:
self.sub = RealSubject(self.filename)
return self.sub.get_content()
def set_content(self, content):
if not self.sub:
self.sub = RealSubject(self.filename)
return self.sub.set_content(content)
# 不使用虚代理
# rs = RealSubject("test.txt")
# rs.set_content("1111")
# rs.get_content()
# 使用虚代理,使用一个代理去操作我们的实体
vp = VirtualProxy("test.txt") # 使用一个代理去操作我们的实体
vp.get_content()
vp.set_content("2222")
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
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
如果需要只有读的权限而没有写的权限,可以使用保护代理
"""
为其它对象提供一种代理以控制对这个对象的访问。角色有抽象实体、实体和代理。应用场景有;下面是不使用虚代理的例子:
**应用场景:**
- 远程代理:为远程的对象提供代理(通过ORM向数据库写值,不用关注数据库是在远程)。
- 虚代理:根据需要创建很大的对象(需要的时候创建对象)。
- 保护代理:控制对原始对象的访问,用于对象有不同的访问权限。
**优点:**
- 远程代理:可以隐藏对象位于远程地址空间的事实
- 虚代理:可以进行优化,例如根据要求创建对象
- 保护代理:允许在访问一个对象时有一些附加的内务处理
不使用虚代理,只要是实例化 RealSubject 类,就会读取这个文件占用内存。使用虚代理后,可以和根据需要创建对象,用户不调用是不会创建 RealSubject 对象的,节省了内存的开销
角色:
抽象实体(Subject)
实体(RealSubject)
代理(Proxy)
"""
from abc import ABCMeta, abstractmethod
# 抽象实体(Subject)
class Subject(metaclass=ABCMeta):
"""读取文件写入文件"""
@abstractmethod
def get_content(self):
pass
@abstractmethod
def set_content(self, content):
pass
# 实体(RealSubject)
class RealSubject(Subject):
def __init__(self, filename):
self.filename = filename
print("读取文件内容!")
with open(self.filename, "r", encoding="UTF-8") as f:
self.centent = f.read()
print(self.centent)
def get_content(self):
return self.centent
def set_content(self, content):
print("写入文件内容!")
with open(self.filename, "w", encoding="UTF-8") as f:
f.write(content)
# 代理(Proxy)
class VirtualProxy(Subject):
def __init__(self, filename):
self.filename = filename
self.sub = None
def get_content(self):
if not self.sub:
self.sub = RealSubject(self.filename)
return self.sub.get_content()
def set_content(self, content):
if not self.sub:
self.sub = RealSubject(self.filename)
return self.sub.set_content(content)
class ProtectedSubject(Subject):
"""保护模式"""
def __init__(self, sub):
self.sub = sub
def get_content(self):
return self.sub.get_content()
def set_content(self, content):
raise Exception("没有写入权限")
# 通过代理对原有的实体类进一步操作
# 不使用虚代理,操作实体类
rs = RealSubject("test.txt")
rs.set_content("1111")
rs.get_content()
# 使用虚代理,使用一个代理去操作我们的实体
vp = VirtualProxy("test.txt") # 使用一个代理去操作我们的实体
vp.get_content()
vp.set_content("2222")
# 保护模式
ps = ProtectedSubject(RealSubject("test.txt"))
ps.get_content()
ps.set_content("44444")
"""
读取文件内容!
2222
写入文件内容!
读取文件内容!
1111
写入文件内容!
读取文件内容!
2222
raise Exception("没有写入权限")
Exception: 没有写入权限
"""
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
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
# 行为模式
# 1. 责任链模式
类和类之间互相关联形成一条链路
1
说明
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链并沿着这条链传递该请求,直到有一个对象处理它为止。责任链的角色有抽象处理者、具体处理者和客户端。
角色:
抽象处理者(Handler)
具体处理者(ConcreteHandler)
客户端(Client)
1
2
3
4
5
6
2
3
4
5
6
适用场景:
- 有多个对象可以处理一个请求,那个对象处理由运行时决定
- 在不明确接收者的请求下,向多个对象中的一个提交一个请求
优点:
- 降低耦合度:一个对象无需知道是其他那一个对象处理其请求
具体实现
"""
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链并沿着这条链传递该请求,直到有一个对象处理它为止。责任链的角色有抽象处理者、具体处理者和客户端。
角色:
抽象处理者(Handler)
具体处理者(ConcreteHandler)
客户端(Client)
其实就是:
通过传递对象实例,一层嵌套一层的去判断,条件满足就输出,不满足,就交给下一个对象执行
"""
from abc import abstractmethod, ABCMeta
# 抽象处理者(Handler)
class Handler(metaclass=ABCMeta):
"""员工请假责任链"""
@abstractmethod
def handle_leave(self, day):
pass
# 具体处理者(ConcreteHandler)
class GeneralManager(Handler):
"""总经理"""
def handle_leave(self, day):
if day <= 10:
print("总经理批准%d" % day)
else:
print("你可以辞职了!")
# 具体处理者(ConcreteHandler)
class DepartmentManager(Handler):
"""部门"""
def __init__(self):
self.next = GeneralManager()
def handle_leave(self, day):
if day <= 5:
print("部门经理批准%d" % day)
else:
print("部门经理权限不足!")
self.next.handle_leave(day)
# 具体处理者(ConcreteHandler)
class ProjectDirector(Handler):
"""项目主管"""
def __init__(self):
self.next = DepartmentManager()
def handle_leave(self, day):
if day <= 3:
print("项目主管批准%d" % day)
else:
print("项目主管权限不足!")
self.next.handle_leave(day)
# 类和类之间互相关联形成一条链路
pd = ProjectDirector() # 无需知道是其它哪一个对象处理其请求
pd.handle_leave(1) # 更具请假天数,来判断需要那个 处理者来处理
pd.handle_leave(3)
pd.handle_leave(7)
pd.handle_leave(11)
"""
项目主管批准1
项目主管批准3
项目主管权限不足!
部门经理权限不足!
总经理批准7
项目主管权限不足!
部门经理权限不足!
你可以辞职了!
"""
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
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
# 2. 观察者模式
说明
观察者模式应用比较广泛,又被称为“发布-订阅”模式。它用来定义对象间一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并被自动更新。
角色:
抽象主题(Subject)
具体主题(ConcreteSubject) -- 发布者
抽象观察者(Observer)
具体观察者(ConcreteObserver) -- 订阅者
1
2
3
4
5
6
7
2
3
4
5
6
7
使用场景
- 当一个抽象模型有两个方面,其中一个方面依赖另一个方面。将这两者封装在独立对象中以使它们可以各自独立地改变和复用
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象待改变
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧耦合的
优点
- 目标和观察者之间的抽象耦合最小
- 支持广播通信
具体实现
"""
观察者模式应用比较广泛,又被称为“发布-订阅”模式。它用来定义对象间一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并被自动更新。
角色:
抽象观察者(Observer)
具体观察者(ConcreteObserver) -- 订阅者(观察者)
抽象主题(Subject)
具体主题(ConcreteSubject) -- 发布者
其实就是:
1、创建一个发布者容器,把订阅者使用attach()放到容器中,通过遍历的方式推送消息
"""
from abc import abstractmethod, ABCMeta
# 抽象观察者(Observer)抽象订阅者
class Observer(metaclass=ABCMeta):
@abstractmethod
def update(self, notice):
pass
# 抽象主题(Subject) 抽象发布者:可以是接口,子类不需要实现,所以不需要定义抽象方法!
class Notice:
def __init__(self):
self.observer = []
def attach(self, obj):
# 将对象添加到列表
self.observer.append(obj)
def detach(self, obj):
# 将对象从列表移除
self.observer.remove(obj)
def notify(self):
"""遍历对象列表推送消息"""
for obj in self.observer:
obj.update(self)
# 具体主题(具体发布者)
class StaffNotice(Notice):
def __init__(self, company_info):
super().__init__() # 调用父类对象声明的observer属性
self.__company_info = company_info
@property
def company_info(self):
return self.__company_info
@company_info.setter
def company_info(self, info):
self.__company_info = info
self.notify()
# 具体的观察者(订阅者)
class Staff(Observer):
def __init__(self):
self.company_info = None
def update(self, notice):
self.company_info = notice.company_info
staff_notice = StaffNotice('初始化公司信息')
staff1 = Staff()
staff2 = Staff()
staff_notice.attach(staff1) # 将观察者添加到主题中
staff_notice.attach(staff2)
staff_notice.company_info = '假期放假通知!'
print(staff1.company_info)
print(staff2.company_info)
staff_notice.detach(staff2) # 将某个观察者移除
staff_notice.company_info = '明天开会!'
print(staff1.company_info)
print(staff2.company_info)
"""
假期放假通知!
假期放假通知!
明天开会!
假期放假通知!
"""
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
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
# 3. 策略模式
说明
定义一个个算法,把它们封装起来,并且使它们可以相互替换。本模式使得算法可独立于使用它的客户而变化.
角色:
抽象策略(Strategy)
具体策略(ConcreteStrategy)
上下文(Context)
1
2
3
4
5
6
2
3
4
5
6
优点
- 定义了一些列可重用的算法和行为
- 消除了一些条件语句
缺点
- 客户必须了解不同的策略
具体实现
"""
定义一个个算法,把它们封装起来,并且使它们可以相互替换。本模式使得算法可独立于使用它的客户而变化.
角色:
抽象策略(Strategy)
具体策略(ConcreteStrategy)
上下文(Context)
其实就是:
1、创建一个抽象策略
2、创建多个具体策略,(表示多个算法)
3、在上下文中执行或者切换
"""
from abc import abstractmethod, ABCMeta
# 抽象策略
class Strategy(metaclass=ABCMeta):
@abstractmethod
def execute(self, data):
pass
# 具体策略
class FastStrategy(Strategy):
def execute(self, data):
print("使用较快的策略处理%s" % data)
# 具体策略
class SlowStrategy(Strategy):
def execute(self, data):
print("使用较慢的策略处理%s" % data)
# 上下文
class Context:
def __init__(self, data, strategy):
self.data = data
self.strategy = strategy
def set_strategy(self, strategy):
"""切换"""
self.strategy = strategy
def do_strategy(self):
"""执行"""
self.strategy.execute(self.data)
data = "Hello!"
# 创建新策略,使用较快的策略处理
fast_strategy = FastStrategy()
context = Context(data, fast_strategy)
context.do_strategy()
# 创建新策略,使用较慢的策略处理
slow_strategy = SlowStrategy()
context.set_strategy(slow_strategy) # 切换策略(切换对象实例)
context.do_strategy()
"""
使用较快的策略处理Hello!
使用较慢的策略处理Hello!
"""
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
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
# 4. 模板方法模式
说明
定义一个操作中的算法骨架,将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:
使用模板方法,需要用到两种角色,分别是
抽象类:抽象类的作用是是定义抽象类(钩子操作),实现一个模板方法作为算法的骨架
具体类:具体类的作用实现原子操作
1
2
3
4
5
6
2
3
4
5
6
模板方法适用的场景
- 一次性实现一个算法的不变部分,各个子类中的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复
- 控制子类扩展
具体实现
"""
定义一个操作中的算法骨架,将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:
使用模板方法,需要用到两种角色,分别是
抽象类:抽象类的作用是是定义抽象类(钩子操作),实现一个模板方法作为算法的骨架
具体类:具体类的作用实现原子操作
其实就是:
1、我定义好具体的方法和流程,只给客户一些需要输入的方法
"""
from abc import ABCMeta, abstractmethod
from time import sleep
# 抽象类
class Window(metaclass=ABCMeta):
@abstractmethod
def start(self): # 原子操作/钩子操作
pass
@abstractmethod
def repaint(self): # 原子操作/钩子操作
pass
@abstractmethod
def stop(self): # 原子操作/钩子操作
pass
def run(self):
"""
模板方法(具体方法),这个大逻辑就不需要自己写了
:return:
"""
self.start()
while True:
try:
self.repaint()
sleep(1)
except KeyboardInterrupt:
break
self.stop()
# 具体类
class MyWindow(Window):
def __init__(self, msg):
self.msg = msg
def start(self):
print('窗口开始运行!')
def stop(self):
print('窗口停止运行!')
def repaint(self):
print(self.msg)
MyWindow("Hello...").run()
"""
窗口开始运行!
Hello...
Hello...
Hello...
Hello...
窗口停止运行!
"""
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
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
1
编辑 (opens new window)
上次更新: 2023/05/17, 23:08:21