设计模式(python)
设计模式
1.设计模式与面向对象简绍


1.python 中接口实现的两种方式

class A:
def run(self, object1):
pass
class B:
def fun(self, object1):
pass
p = A()
def total_run(p, object1):
p.run(object1)
# 调用不同的类的 方法名相同,方法的参数相同, (限制接口的调用方式)
# 在父类中定义 抽象接口, 子类继承父类,子类必须以同样的函数名和参数实现父类的方法, 如果子类未定义,会抛出异常,
# 问题: 抛出异常的时刻在 调用对象方法的时候, 如果不调用 对象方法不报错
class Base:
def run(self, object1):
raise NotImplementedError
class A(Base):
def run(self, object1):
pass
class B(Base):
def fun(self, object1):
pass
p = A()
def total_run(p, object1):
p.run(object1)


# 使用抽象类,抽象方法, 抽象类继承 ABCMeta 类, 抽象类中的方法使用 @abstractmethod 装饰器装饰
# 有抽象方法的类叫做抽象类, 抽象类不能实例化, 子类重写父类的方法, 那么子类中就没有抽象方法了(和 c++ 中的多态有点相似)就可以实例化了
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
# def pay(self, money):
# pass
pass
class WecharPay(Payment):
def pay(self, money):
pass
p = Alipay()

2.面向对象设计原则

# 里氏替换原则
# 例如 下面两个类, 父类和子类应该返回相同的对象。父类和子类应该有相同的 调用方式(使用方式)
class User:
def show_name(self):
pass
class VIPUser(User):
def show_name(self):
pass
u = User()
res = u.show_name()
# 依赖倒置原则
"""
高层代码:在这里, 例如是一些需要调用 pay 方法的代码
底层代码: 每中 不同的 pay 方法的具体实现,例如 alipay, wechatpay
定义一个抽象类, 底层代码继承 抽象类进行实现,具有统一的调用方式, 高层代码 依赖 抽象类, 而不依赖底层代码
抽象不依赖细节, 细节依赖抽象, : 先写接口,实现外在表现由接口限制(人话)
"""
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
# def pay(self, money):
# pass
pass
class WechatPay(Payment):
def pay(self, money):
pass
p = Alipay()

接口隔离原则,例如下图, tiger 类继承 animal 类,tiger(老虎) 只有走行为,如果继承总的接口 animal 类就需要实现一些 tiger 类本身不需要的方法, 例如 swim, fly , 设计不合理。

# 接口隔离原则, 使用专门的接口, 而不使用单一的总接口
from abc import ABCMeta, abstractmethod
class landAnimal(metaclass=ABCMeta):
@abstractmethod
def walk(self):
pass
class WaterAnimal(metaclass=ABCMeta):
@abstractmethod
def swim(self):
pass
class SkyAnimal(metaclass=ABCMeta):
@abstractmethod
def fly(self):
pass
class Tiger(landAnimal):
def walk(self):
print("Tiger is walking")
3.设计模式分类

4.简单工程模式

"""
一个抽象类, 一些具体实现继承 抽象类, 创建一个类 根据传递的参数的不同,调用不同的类,可以在调用类中设置一些默认的参数,通过工厂类(PaymentFactory)调用具体的 对象
"""
from abc import ABCMeta, abstractmethod
# 抽象产品角色
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
# 具体产品角色
class Alipay(Payment):
def pay(self, money):
print("111")
# 具体产品角色
class WechatPay(Payment):
def pay(self, money):
pass
# 工厂角色
class PaymentFactory:
def create_payment(self, method):
if method == "alipay":
return Alipay()
elif method == "wechat":
return WechatPay()
else:
raise TypeError("No such payment named %s" %(method))
# client
pf = PaymentFactory()
p = pf.create_payment("alipay")
p.pay(100000)

5.工厂方法模式

"""
工厂方法模式, 将工厂角色进行抽象, 不同的工厂角色有不同的实现
使用 抽象工厂角色和 具体工厂角色, 可以在工厂调用的工厂中 传递一些不需要上层代码传递的参数, 可以隐藏一些细节, 简化高层调用。
"""
from abc import ABCMeta, abstractmethod
# 抽象产品角色
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
# 具体产品角色
class Alipay(Payment):
def pay(self, money):
print("111")
# 具体产品角色
class WechatPay(Payment):
def pay(self, money):
pass
# 抽象 工厂角色
class PaymentFactory(metaclass=ABCMeta):
@abstractmethod
def create_payment(self):
pass
# 具体工厂角色
class AlipayFactory(PaymentFactory):
def create_payment(self):
return Alipay()
# 具体工厂角色
class WechatPayFactory(PaymentFactory):
def create_payment(self):
return WechatPay()
pf = AlipayFactory()
p = pf.create_payment()
p.pay(1000)

6.抽象工厂模式

from abc import abstractmethod, ABCMeta
# ------- 抽象产品 -----
class PhoneShell(metaclass=ABCMeta):
@abstractmethod
def show_shell(self):
pass
class CPU(metaclass=ABCMeta):
@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):
pass
@abstractmethod
def make_os(self):
pass
# ----- 具体产品 ----
class SmallShell(PhoneShell):
def show_shell(self):
print("普通手机小手机壳")
class BigShell(PhoneShell):
def show_shell(self):
print("普通手机大手机壳")
class AppleShell(PhoneShell):
def show_shell(self):
print("苹果手机壳")
class SnapDragonCPU(CPU):
def show_cpu(self):
print("晓龙CPU")
class MediaTekCPU(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 MiFactory(PhoneFactory):
def make_cpu(self):
return SnapDragonCPU()
def make_os(self):
return Android()
def make_shell(self):
return BigShell()
# --- client ---
class Phone:
def __init__(self, cpu, os, shell):
self.cpu = cpu
self.os = os
self.shell = shell
def show_info(self):
print("phone message")
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(MiFactory())
p1.show_info()



7.建造者模式

from abc import ABCMeta, abstractmethod
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 "%s, %s, %s, %s" % (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 SexyGirlBuilder(PlayerBuilder):
def __init__(self):
self.player = Player()
def build_face(self):
self.player.face = "beautiful face"
def build_body(self):
self.player.body = "苗条"
def build_arm(self):
self.player.arm = "beautiful arm"
def build_leg(self):
self.player.leg = "long leg"
class Monster(PlayerBuilder):
def __init__(self):
self.player = Player()
def build_face(self):
self.player.face = "ugly face"
def build_body(self):
self.player.body = "大大"
def build_arm(self):
self.player.arm = "ugly arm"
def build_leg(self):
self.player.leg = "short leg"
class PlayerDirector:
def build_players(self, builder):
# 控制对象的组装顺序
builder.build_body()
builder.build_face()
builder.build_arm()
builder.build_leg()
return builder.player
# client
builder = SexyGirlBuilder()
director = PlayerDirector()
p = director.build_players(builder)
print(p)
builder = Monster()
director = PlayerDirector()
p = director.build_players(builder)
print(p)


8.单例模式

class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
class MyClass(Singleton):
def __init__(self, a):
self.a = a
a = MyClass(10)
b = MyClass(20)
print(a.a) # 20
print(b.a) # 20
print(id(a)) # 2394949577296
print(id(b)) # 2394949577296

9.适配器模式


"""
两个系统合并成一个新的系统, 支付方法中的方法名不一样,bankpay 中使用的 cost 方法,其他使用的是 pay 方法
底层支付代码在 高层代码中都有使用, 不能够直接的修改 方法名
可以使用 适配器
"""
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
def pay(self, money):
print("支付宝支付%d元" % money)
class WechatPayment(Payment):
def pay(self, money):
print("微信支付%d元" % money)
class BankPay:
def cost(self, money):
print("银联支付%d元" % money)
p = BankPay()
p.pay(100)

from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
def pay(self, money):
print("支付宝支付%d元" % money)
class WechatPayment(Payment):
def pay(self, money):
print("微信支付%d元" % money)
class BankPay:
def cost(self, money):
print("银联支付%d元" % money)
# 类适配器
# 适配器
class NewBankPay(Payment, BankPay):
def pay(self, money):
self.cost(money)
p = NewBankPay()
p.pay(100)
# 组合 在一个类中放入另一个类的对象
class A:
pass
class B:
def __init__(self):
self.a = A()
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
def pay(self, money):
print("支付宝支付%d元" % money)
class WechatPayment(Payment):
def pay(self, money):
print("微信支付%d元" % money)
class BankPay:
def cost(self, money):
print("银联支付%d元" % money)
class ApplePay:
def cost(self, money):
print("苹果字符 %d元" % money)
# 对象适配器
# 使用组合, 在一个类中复用另一个类中的代码
class PaymentAdapter(Payment):
def __init__(self, payment):
self.payment = payment
def pay(self, money):
self.payment.cost(money)
p = PaymentAdapter(ApplePay())
p.pay(100)
p = PaymentAdapter(BankPay())
p.pay(100)

10.桥模式

"""
例如一个画图软件, 有 形状 和 颜色两个维度,
可以使用如下方式实现, 3 个颜色, 3个形状, 两两组合需要 9个类, 不易扩展
"""
class Shape:
pass
class Line(Shape):
pass
class Rectangle(Shape):
pass
class Circle(Shape):
pass
class RedLine(Line):
pass
class GreenLine(Line):
pass
class BuleLine(Line):
pass
# 桥接模式
from abc import ABCMeta, abstractmethod
# 抽象类
# 通过组合的方式, 将形状和 颜色组合起来
class Shape(metaclass=ABCMeta):
def __init__(self, color):
self.color = color
@abstractmethod
def draw(self):
pass
# 抽象类
class Color(metaclass=ABCMeta):
@abstractmethod
def paint(self, shape):
pass
class Rectangle(Shape):
name = "长方形"
def draw(self):
# 长方形逻辑
self.color.paint(self)
class Circle(Shape):
name = "圆形"
def draw(self):
# 圆形逻辑
self.color.paint(self)
class Red(Color):
def paint(self, shape):
print("红色的%s" % shape.name)
class Green(Color):
def paint(self, shape):
print("绿色的%s" % shape.name)
shape = Rectangle(Red())
shape.draw()
shape = Circle(Green())
shape.draw()



11.组合模式

from abc import ABCMeta, abstractmethod
# 抽象组件
class Graphic(metaclass=ABCMeta):
@abstractmethod
def draw(self):
pass
# 叶子组件
class Point(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))
# 叶子组件
class Line(Graphic):
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
def __str__(self):
return "线段[%s, %s]" % (self.p1, self.p2)
def draw(self):
print(str(self))
# 复合组件
class Picture(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):
print("----复合图形-----")
for g in self.children:
g.draw()
print("----复合图形-----")
"""
一个线段由两个点组成, 写一个抽象的图像类, 一个点类, 一个线段类
线段由 两个点组成, 线段对象接收两个 点类的对象, 组合成 线段对象
"""
l = Line(Point(1, 1), Point(2, 2))
print(l)
p1 = Point(2, 3)
l1 = Line(Point(3, 4), Point(6, 7))
l2 = Line(Point(1, 5), Point(2, 8))
pic = Picture([p1, l1, l2])
pic.draw()



12.外观模式

# 子系统类
class CPU:
def run(self):
print("CPU 开始运行")
def stop(self):
print("CPU停止运行")
# 子系统类
class Disk:
def run(self):
print("硬盘开始工作")
def stop(self):
print("硬盘停止工作")
# 子系统类
class Memory:
def run(self):
print("内存通电")
def stop(self):
print("内存断电")
# 外观, facade
class Computer:
def __init__(self):
self.cpu = CPU()
self.disk = Disk()
self.memory = Memory()
def run(self):
self.cpu.run()
self.disk.run()
self.memory.run()
def stop(self):
self.cpu.stop()
self.disk.stop()
self.memory.stop()
computer = Computer()
computer.run()
computer.stop()

13.代理模式

"""
一个抽象类, 一个真实的类, 在 初始化方法的时候,打开文件并读取内容, 调用 get_content 方法的时候,从类中获取数据,调用 set_content 方法的时候, 设置文件内容, 没有调用 get_content 的方法的时候, 文件内容就已经保存到类中了, 比较占内存, 使用代理模式 去调用 真实的类, 虚代理, 虚代理类在初始化的时候,不读取文件的内容
在调用 get_content 的时候,才 读取文件内容
通过增加一个新的类, 对已有的类进行 二次封装改造,达到 代理的作用。
"""
from abc import ABCMeta, abstractmethod
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("读取文件内容")
f = open(filename, "r", encoding="utf-8")
self.content = f.read()
f.close()
def get_content(self):
return self.content
def set_content(self, content):
f = open(self.filename, "w", encoding="utf-8")
f.write(content)
f.close()
# 虚代理
class VirtualProxy(Subject):
def __init__(self, filename):
self.filename = filename
self.subj = None
def get_content(self):
if not self.subj:
self.subj = RealSubject(self.filename)
return self.subj.get_content()
def set_content(self, content):
if not subj:
self.subj = RealSubject(self.filename)
return self.subj.set_content(content)
# 保护代理
class ProtectedProxy(Subject):
def __init__(self, filename):
self.subj = RealSubject(filename)
def get_content(self):
return self.subj.get_content()
def set_content(self, content):
raise PermissionError("无写入权限")
subj = RealSubject("data.txt")
sub = VirtualProxy("data.txt")
print(subj.get_content())
subj = ProtectedProxy("data.txt")
print(subj.get_content())
subj.set_content("abc")

13.责任链模式


"""
请假的例子, 请假天数小于等于 3天, 项目主管有权限 批准, 小于等于 5 天, 部门经理有权限批准
小于等于10天, 总经理有权限批准
写一个抽象处理者, 有三个 具体处理者, 项目经理类, 部门经理类, 总经理类,
client 端调用 项目经理类进行请假, 如果 权限不足, 调用上级对象处理
类似于数据结构中的链表
"""
from abc import ABCMeta, abstractmethod
# 抽象处理者
class Handler(metaclass=ABCMeta):
@abstractmethod
def handle_leave(self, day):
pass
# 具体处理者
class GeneralManager(Handler):
def handle_leave(self, day):
if day <= 10:
print("总经理准假%d" % day)
else:
print(",,,,")
# 具体处理者
class DepartmetManager(Handler):
def __init__(self):
self.next = GeneralManager()
def handle_leave(self, day):
if day <= 5:
print("部门经理准假%s天" % day)
else:
print("部门经理职权不足")
self.next.handle_leave(day)
# 具体处理者
class ProjectDirector(Handler):
def __init__(self):
self.next = DepartmetManager()
def handle_leave(self, day):
if day <= 3:
print("项目主管准假%d天" % day)
else:
print("项目主管职权不足")
self.next.handle_leave(day)
# client
day = 11
h = ProjectDirector()
h.handle_leave(day)

14.观察者模式


from abc import ABCMeta, abstractmethod
class Observer(metaclass=ABCMeta): # 抽象订阅者
@abstractmethod
def update(self, notice): # notice 是一个 Notice 类的对象
pass
class Notice: # 抽象发布者
def __init__(self):
self.observers = []
def attach(self, obs):
self.observers.append(obs)
def detach(self, obs):
self.observers.remove(obs)
def notify(self): # 推送
for obs in self.observers:
obs.update(self)
class StaffNotice(Notice): # 具体发布者
def __init__(self, company_info=None):
super().__init__()
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
notice = StaffNotice("初始公司信息")
s1 = Staff()
s2 = Staff()
notice.attach(s1)
notice.attach(s2)
notice.company_info = "发奖金 !!!"
print(s1.company_info)
print(s2.company_info)
notice.detach(s2)
notice.company_info = "不发奖金 !!!"
print(s1.company_info)
print(s2.company_info)

15.策略模式

"""
定义一个抽象策略接口 , 定义两个具体策略类, 定义一个上下文, 来设置不同的策略类
比如,打车时, 平台 匹配用户和 车辆的策略
"""
from abc import ABCMeta, abstractmethod
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, strategy, data):
self.data = data
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def do_strategy(self):
self.strategy.execute(self.data)
# Client
data = "[....]"
s = FastStrategy()
s1 = SlowStrategy()
context = Context(s, data)
context.do_strategy()
context.set_strategy(s1)
context.do_strategy()

16.模版方法模式

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): # 模版方法
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()

17.总结

通过一些特别的场景的例子,来了解设计模式的使用方法,学习设计思想。

浙公网安备 33010602011771号