设计模式(python描述)
目录
一、创建型设计模式 1、简单工厂模式 内容: 不直接向高层类暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。 角色:
python示例: from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): """ 抽象产品角色 # 抽象类,必须子类必须实现这个方法。 """ @abstractmethod def pay(self,money): pass class Alipay(Payment): """ 具体产品角色 """ def __init__(self,huabei=False): self.huabei = huabei def pay(self,money): if slelf.huabei: print("花呗支付%d元" % money) else: print("支付宝支付%d元" % money) class WechatPay(Payment): def pay(self,money): print("微信支付%d元" % money) class PaymentFactory: ‘‘‘ 工厂角色 可以这这里统一处理参数问题,或者返回值的问题。 比如一个对象是一个参数,另一个对象是两个参数。可以通过这个类来处理一下。 ‘‘‘ def create_payment(self,method): if method == ‘alipay‘: return Alipay() elif method == ‘wechat‘: return WechatPay() elif method == ‘huabei‘: return Alipay(huabei=True) else: rasie TypeError(‘No such class named %s‘ % method) pf = PaymentFactory() p = pf.create_payment(‘huabei‘) p.pay(100) 优点:
缺点:
例如,如果现在有一个ApplePayment的pay接口,需要支付,那么就必须改动工厂角色的代码,使之能支持新的扩展。 class ApplePay(Payment): def pay(self,money): print("苹果支付%d元" % money) class PaymentFactory: def create_payment(self,method): if method == ‘alipay‘: return Alipay() elif method == ‘wechat‘: return WechatPay() elif method == ‘huabei‘: return ApplePay(huabei=True) elif method == ‘apple‘: return Alipay() else: rasie TypeError(‘No such class named %s‘ % method) 这样,明显违背了开闭原则,以及单一职责原则。对程序扩展是十分不便的。 2、工厂方法模式 内容: 定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。 角色:
python示例: from abc import ABCMeta,money): print("微信支付%d元" % money) class PaymentFactory(metaclass=ABCMeta): @abstractmethod def create_payment(self,method): pass 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) hf = HuaBeiFactory() p = hf.create_payment() p.pay(100) 工厂方法模式,使原来的工厂角色,细分称为了抽象工厂角色,和具体工厂角色。这样,符合单一职责原则,一个工厂方法只做了一件事。并且也符合开闭原则,如果要扩展新的支付接口,只需要重新写一个具体产品角色,和具体工厂角色。 class ApplePay(Payment): def pay(self,money): print("苹果支付%d元" % money) class AppleFactory(PaymentFactory): def create_payment(self): return ApplePay() 优点:
缺点:
如果要是接口很多的话,这样就会有很多的类出现在代码中。 3、抽象工厂模式 内容: 定义一个工厂类接口,让工厂子类来创建一系列相关或者相互依赖的对象。 角色:
python示例: 生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。 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): ‘‘‘ 抽象工厂 ‘‘‘ @abstratmethod def make_shell(self): pass @abstratmethod def make_cpu(self): pass @abstratmethod def make_os(self): pass # 具体产品角色 class SmallShell(PhoneShell): def show_shell(slef): print("普通手机小手机壳") class BigShell(PhoneShell): def show_shell(slef): print("普通手机大手机壳") class AppleShell(PhoneShell): def show_shell(slef): print("苹果手机壳") class SnapDragonCPU(CPU): def show_cpu(slef): print("骁龙CPU") class MediaTekCPU(CPU): def show_cpu(slef): print("联发科CPU") class AppleCPU(CPU): def show_cpu(slef): print("苹果手机CPU") class Andriod(OS): def show_os(slef): print("Andriod系统") class IOS(OS): def show_os(slef): print("IOS系统") # 具体工厂角色 class MiFactory(PhoneFactory): def make_shell(self): return BigShell() def make_cpu(self): return SnapDragonCPU() def make_os(self): return Android() class HuaweiFactory(PhoneFactory): def make_shell(self): return SmallShell() def make_cpu(self): return MediaTekCPU() def make_os(self): return Android() class IPhone(PhoneFactory): def make_shell(self): return AppleShell() def make_cpu(self): return AppleCPU() def make_os(self): return IOS() # 高层模块/客户端 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,shell) p1 = make_phone(MiFactory()) p1.show_info() 优点:
缺点:
如果我的手机现在不只是由手机壳、CPU、操作系统组成,还有硬盘,那么就必须对抽象工厂和具体工厂类进行修改来支持新的产品。 4、建造者模式 内容: 角色:
python示例: 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. %sm. %s,%s‘ % (self.face,self.body,self.arm,self.leg) # 抽象建造者 class PlayerBuild(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(PlayerBuild): 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 Monster(PlayerBuild): 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 PlayerDiector: # 控制组装顺序 def build_play(self,builder): builder.build_body() builder.build_face() builder.build_arm() builder.build_leg() return builder.player # 产品 builder = SexyGirlBuilder() director = PlayerDirector() p = director.build_player(builder) print(p) 建造者模式与抽象工厂模式相似,用是用来创建复杂对象,主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。 优点:
5、单例模式 内容: 保证一个类只有一个实例,并提供一个访问它的全局访问点。 角色:
python示例: class Singleton: def __new__(cls,*args,**kwargs): if not hasattr(cls,‘__instance‘): cls._instence = super(Singleton,cls).__new__(cls): return cls._instance class MyClass(Singleton): def __init__(self): self.a = a a = MyClass(10) b = MyClass(20) class SingleTon(type): def __init__(self,classname,fatherclass,dic): super(SingleTon,self).__init__(classname,dic) def __call__(self,**kwargs): if not hasattr(self,‘singleton‘): obj = object.__new__(self) self.singleton = self.__init__(obj,**kwargs) return self.singleton class Person(metaclass=SingleTon): def __init__(self): self.name = ‘walle‘ p = Person() p1 = Person() print(id(p)) print(id(p1)) 优点:
二、结构型设计模式 1、适配器模式 内容: 将一个类的接口转化成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能再一起工作的那些类可以在一起工作。 角色:
实现方式:
python示例: 还是支付接口,如果银联支付的接口与其他支付的接口不一样。当两个系统合并的时候,就会出现问题。因此,需要一个适配器将接口进行统一。 from abc import ABCMeta,money): print("支付宝支付%d元" % money) class WechatPay(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 NewBankPay(Payment,BankPay): def pay(self,money): self.cost() # 对象适配器,通过组合来完成代码复用,推荐。 class PaymentAdapter(Payment): def __init__(self,payment): self.payment = payment def pay(self,money): self.payment.cost(money) # p = Alipay() p = NewBankPay() p.pay(100) 当然使用组合适配器更加的灵活与反方便。 使用场景:
2、桥模式 内容: 将一个事物的两个维度分类,使其都可以独立地变化。 角色:
python示例: 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 Cirlce(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() shape2 = Circle(Green()) shape2.draw() 这种利用组合的结构是一种松耦合的方式,如果要扩展颜色,或者形状,只需要加上对应的类就可以了。有就是说在这两个维度上都可以进行任意的扩展。不用添加代码,或者修改代码。 class Line(Shape): name = ‘直线‘ def draw(self): self.color.paint(self) class Blue(color): def paint(self,shape): print("蓝色的%s"%shape.name) 应用场景
优点:
3、组合模式 内容: 将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 角色:
python示例 from abc import ABCMeta,abstractmethod # 抽象组件 class Graphic(metaclass=ABCMeta): @abstractmethod def draw(self): pass # 叶子组件 class Point(Graphic): def __init__(self): 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): 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(‘---复合图形---‘) p1 = Point(2,3) l1 = Line(Point(3,4),Point(6,7)) l2 = Line(Point(1,5),Point(2,8)) pic1 = Picture([p1,l1,l2]) pic1.draw() p2 = Poine(4,4) l3 = Line(Point(1,1),Point(1,0)) pic2 = Picture([p2,l2]) pic = Picture([pic1,pic2]) pic.draw() 使用场景:
优点:
4、外观模式 内容: 为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 角色:
python示例 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("内存断点") 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() 优点:
5、代理模式 内容: 为其他对象提供一种代理以控制对这个对象的访问。 角色:
应用场景:
python示例 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 f = open(filename) print("读取数据") self.content = f.read() f.close() def get_content(self): return self.content def set_content(self): f = open(self.filename,‘w‘) f.write(content) f.close() # 当文件很大,不用虚代理,当创建对象的时候,会占用很大的内存,即使不执行get_content(),内存也会被占用。 class VirtualProxy(Subject): """ 虚代理 """ def __init__(self,filename): self.filename = filename self.suj = None def get_content(self): if not self.subj: self.subj = RealSubject(self.filename) return self.subj.get_content() def set_content(self): if not self.subj: self.subj = RealSubject(self.filename) return self.subj.set_content() subj = RealSubject(‘test.txt‘) #创建对象的时候就需要将数据读取到内存。 subj.get_content() subj1 = VirtualProxy(‘test.txt‘) #创建对象的时候只需要放一个变量。 subj1.get_content() class ProtectProxy(Subject): def __init__(self,filename): self.subj = RealSubject(filename) def get_content(self): return self.subj.get_content() def set_content(self,content): rasise PermisssionError("无写入权限") subj = ProtectProxy(‘test.text‘) subj.set_content(‘abc‘) 优点:
三、行为型设计模式 1、责任链模式 内容: 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 角色:
python示例 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 dat < 10: print("总经理准假%d天"%day) else: print("你还是辞职吧") class DepartmentManager(Handler): def __init__(self): self.next = GeneralManager() def handler_leave(self,day): if day <= 5: print("部门经理准假%d天" % day) else: print("部门经理职权不足") self.next.handle_leave(day) class ProjectDirector(Hadnler): def __init__(self): self.next = DepartmentManager() def handler_leave(self,day): if day <= 1: print("项目主管准假%d天" % day) else: print("项目主管职权不足") self.next.handler_leave(day) day = 4 h = ProjectDirctor() h.handle_leave(day) 使用场景:
优点:
scrapy的pipline的实现就是用的责任链模式。 2、观察者模式 内容: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式。 当发布者的状态发生变化的时候,这些订阅者就会自动去更新,而不再是需要判断,手动更新。 发布者跟订阅者之间的关系,应该是一个松耦合的。也就是对于订阅者而言,可以取消订阅。 角色:
python示例 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): super().__init__() self.__company_info = comany_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) notice.detach(s2) notice.company_info = "公司明天放假!!" print(s1.company_info) print(s2.company_info) 使用场景:
优点:
3、策略模式 内容: 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。本模式使得算法可独立于使用它的客户而变化。 角色:
Python示例 例如:网约车。当一个人要打车的时候,需要匹配车辆,这个时候算法需要考虑几个方面,距离近(地图网络距离),司机评分要好,价格等。 现在有两个算法,都能匹配到司机。 这两个算法会不断的切换,比如订单的高峰期,可能会用第二个(快但不准),低峰期的时候用算法一(准确并且性价比好)。 from abc import ABCMeta,abcstractmethod class Strategy(metaclass=ABCMeta): @abcstractmethod def execute(self,data): pass class FastStratege(Strategy): def execute(self,data): print("用较快的策略处理%s"%data) class SlowStratege(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) data = "[...]" s1 = FastStrategy() context = Context(s1,data) context.do_strategy() s2 = SlowStrategy() context.set_strategy(s2,data) context.do_strategy() 4、模板方法模式 内容: 定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可冲定义该算法的某些特定步骤。 角色:
python示例 from abc import ABCMeta,abcstractmethod import time 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() time.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() 使用场景:
python是动态语言,因此在设计模式中,并不是百分百跟设计模式切合。但是有大半部分还是有很用的,对写出漂亮的代码很有帮助。设计模式,当写一些大的项目,跟底层的开源项目的时候,会很有用,因为是给别人用的代码,因此需要写的严谨一些。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |