标签:实体 general 对象创建 tar 灵活 hide 提取 ret rem
Christopher Alexander:“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样你就能一次又一次地使用该方案而不必做重复劳动。”
设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。
起初,你会认为“模式”就是为了解决一类特定问题而特别想出来的明智之举。说的没错,看起来的确是通过很多人一起工作,从不同的角度看待问题进而形成的一个最通用、最灵活的解决方案。也许这些问题你曾经见过或是曾经解决过,但是你的解决方案很可能没有模式这么完备。
虽然被称为“设计模式”,但是它们同“设计“领域并非紧密联系。设计模式同传统意义上的分析、设计与实现不同,事实上设计模式将一个完整的理念根植于程序中,所以它可能出现在分析阶段或是更高层的设计阶段。很有趣的是因为设计模式的具体体现是程序代码,因此可能会让你认为它不会在具体实现阶段之前出现(事实上在进入具体实现阶段之前你都没有意识到正在使用具体的设计模式)。
可以通过程序设计的基本概念来理解模式:增加一个抽象层。抽象一个事物就是隔离任何具体细节,这么做的目的是为了将那些不变的核心部分从其他细节中分离出来。当你发现你程序中的某些部分经常因为某些原因改动,而你不想让这些改动的部分引发其他部分的改动,这时候你就需要思考那些不会变动的设计方法了。这么做不仅会使代码可维护性更高,而且会让代码更易于理解,从而降低开发成本。
三种最基本的设计模式:
接口:一种特殊的类,声明了若干方法,要求继承该接口的类必须实现这些方法。
作用:限制继承接口的类的方法的名称及调用方式;隐藏了类的内部实现。
接口就是一种抽象的基类(父类),限制继承它的类必须实现接口中定义的某些方法。
Python中使用ABCMeta、abstractmethod的抽象类、抽象方法来实现接口的功能。接口类定义方法,不具体实现,限制子类必须有该方法。在接口子类中实现具体的功能。
# 通过抽象类和抽象方法,做抽象用 from abc import ABCMeta from abc import abstractmethod # 导入抽象方法 class Father(metaclass=ABCMeta): # 创建抽象类 @abstractmethod def f1(self): pass @abstractmethod def f2(self): pass class F1(Father): def f1(self): pass def f2(self): pass def f3(self): pass obj = F1()
class Interface: def method(self, arg): raise NotImplementedError
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
角色:
优点:
缺点:
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass class Alipay(Payment): def __init__(self, enable_yuebao=False): self.enable_yuebao = enable_yuebao def pay(self, money): if self.enable_yuebao: print("余额宝支付%s元" % money) else: print("支付宝支付%s元" % money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元" % money) class PaymentFactory: def create_payment(self, method): if method == "alipay": return Alipay() elif method == ‘yuebao‘: return Alipay(enable_yuebao=True) elif method == "applepay": return ApplePay() else: raise NameError(method) f = PaymentFactory() p = f.create_payment("yuebao") p.pay(100)
内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色:
工厂方法模式相比简单工厂模式将每个具体产品都对应了一个具体工厂。
适用场景:
优点:
缺点:
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass class Alipay(Payment): def pay(self, money): print("支付宝支付%s元" % money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元" % money) class PaymentFactory(metaclass=ABCMeta): @abstractmethod def create_payment(self): pass class AlipayFactory(PaymentFactory): def create_payment(self): return Alipay() class ApplePayFactory(PaymentFactory): def create_payment(self): return ApplePay() af = AlipayFactory() ali = af.create_payment() ali.pay(120)
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
例:生产一部手机,需要手机壳、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): @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() class HuaweiFactory(PhoneFactory): def make_cpu(self): return MediaTekCPU() 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()
内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
角色:
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
适用场景:
优点:
from abc import abstractmethod, ABCMeta # ------产品------ class Player: def __init__(self, face=None, body=None, arm=None, leg=None): self.face = face self.arm = arm self.leg = leg self.body = body def __str__(self): return "%s, %s, %s, %s" % (self.face, self.arm, self.body, self.leg) # ------建造者------ class PlayerBuilder(metaclass=ABCMeta): @abstractmethod def build_face(self): pass @abstractmethod def build_arm(self): pass @abstractmethod def build_leg(self): pass @abstractmethod def build_body(self): pass @abstractmethod def get_player(self): pass class BeautifulWomanBuilder(PlayerBuilder): def __init__(self): self.player = Player() def build_face(self): self.player.face = "漂亮脸蛋" def build_arm(self): self.player.arm = "细胳膊" def build_body(self): self.player.body = "细腰" def build_leg(self): self.player.leg = "长腿" def get_player(self): return self.player class PlayerDirector: def build_player(self, builder): builder.build_body() builder.build_arm() builder.build_leg() builder.build_face() return builder.get_player() director = PlayerDirector() builder = BeautifulWomanBuilder() p = director.build_player(builder) print(p)
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
角色:
适用场景
优点:
与单例模式功能相似的概念:全局变量、静态变量(方法)
实现:
class Singleton(object): def __new__(cls, *args, **kw): if not hasattr(cls, ‘_instance‘): cls._instance = super(Singleton, cls).__new__(cls, ) return cls._instance class MyClass(Singleton): a = 1 def __init__(self, name): self.name = name one = MyClass(‘egon‘) two = MyClass(‘alex‘) print(id(one)) print(id(two)) print(one == two) print(one is two)
def singleton(cls, *args, **kw): instances = {} def get_instance(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return get_instance @singleton class MyClass2: a = 1 one = MyClass2() two = MyClass2() print(id(one)) # 31495472 print(id(two)) # 31495472 print(one == two) print(one is two)
# Python的模块是天然的单例模式。 # module_name.py class MySingleton(object): def foo(self): print(‘danli‘) my_singleton = MySingleton() # to use from .module_name import my_singleton my_singleton.foo() print(id(my_singleton)) from .module_name import my_singleton my_singleton.foo() print(id(my_singleton))
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] # Python2 # class MyClass: # __metaclass__ = Singleton # Python3 class MyClass(metaclass=Singleton): pass one = MyClass() two = MyClass() print(id(one)) print(id(two)) print(one == two) print(one is two)
内容:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
使用场景:
import copy class Prototype: def __init__(self): self._objects = {} def register_object(self, name, obj): """Register an object""" self._objects[name] = obj def unregister_object(self, name): """Unregister an object""" del self._objects[name] def clone(self, name, **attr): """Clone a registered object and update inner attributes dictionary""" obj = copy.deepcopy(self._objects.get(name)) obj.__dict__.update(attr) return obj def main(): class A: def __str__(self): return "I am A" a = A() prototype = Prototype() prototype.register_object(‘a‘, a) b = prototype.clone(‘a‘, a=1, b=2, c=3) print(a) print(b.a, b.b, b.c) if __name__ == ‘__main__‘: main()
使用抽象工厂(Abstract Factory)、原型(Prototype)或者建造者(Builder)的设计甚至比工厂方法(Factory Method)的那些设计更灵活,但它们也更加复杂。通常,设计以使用工厂方法(Factory Method)开始。并且当设计者发现需要更大的灵活性时,设计便会想其他创建模式烟花。当你在设计标准之间权衡的时候,了解多个模式可以给你提供给更多的选择余地。
依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式、创建者模式
内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
角色:
两种实现方式:
适用场景:
类适配器:
对象适配器:
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): raise NotImplementedError class Alipay(Payment): def pay(self, money): print("支付宝支付%s元" % money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元" % money) # ------待适配类------ class WechatPay: def cost(self, money): print("微信支付%s元" % money) # 类适配器 class RealWechatPay(WechatPay, Payment): def pay(self, money): return self.cost(money) # 对象适配器 class RealWechatPay2(Payment): def __init__(self): self.payment = WechatPay() def pay(self, money): return self.payment.cost(money) p = RealWechatPay2() p.pay(111)
内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
角色:
适用场景:
优点:
缺点:
from abc import abstractmethod, ABCMeta class Graphic(metaclass=ABCMeta): @abstractmethod def draw(self): pass @abstractmethod def add(self, graphic): pass def getchildren(self): pass # 图元 class Point(Graphic): def __init__(self, x, y): self.x = x self.y = y def draw(self): print(self) def add(self, graphic): raise TypeError def getchildren(self): raise TypeError def __str__(self): return "点(%s, %s)" % (self.x, self.y) class Line(Graphic): def __init__(self, p1, p2): self.p1 = p1 self.p2 = p2 def draw(self): print(self) def add(self, graphic): raise TypeError def getchildren(self): raise TypeError def __str__(self): return "线段[%s, %s]" % (self.p1, self.p2) class Picture(Graphic): def __init__(self): self.children = [] def add(self, graphic): self.children.append(graphic) def getchildren(self): return self.children def draw(self): print("------复合图形------") for g in self.children: g.draw() print("------END------") pic1 = Picture() point = Point(2,3) pic1.add(point) pic1.add(Line(Point(1,2), Point(4,5))) pic1.add(Line(Point(0,1), Point(2,1))) pic2 = Picture() pic2.add(Point(-2,-1)) pic2.add(Line(Point(0,0), Point(1,1))) pic = Picture() pic.add(pic1) pic.add(pic2) pic.draw() #pic1.draw() #point.draw()
内容:为其他对象提供一种代理以控制对这个对象的访问。
角色:
适用场景:
优点:
from abc import ABCMeta, abstractmethod class Subject(metaclass=ABCMeta): @abstractmethod def get_content(self): pass def set_content(self, content): pass class RealSubject(Subject): def __init__(self, filename): self.filename = filename print("读取%s文件内容" % filename) f = open(filename) self.__content = f.read() f.close() def get_content(self): return self.__content def set_content(self, content): f = open(self.filename, ‘w‘) f.write(content) self.__content = content f.close() # ---远程代理 class ProxyA(Subject): def __init__(self, filename): self.subj = RealSubject(filename) def get_content(self): return self.subj.get_content() def set_content(self, content): return self.subj.set_content(content) # ---虚代理 class ProxyB(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() x = ProxyB(‘abc.txt‘) # print(x.get_content()) # ---保护代理 class ProxyC(Subject): def __init__(self, filename): self.subj = RealSubject(filename) def get_content(self): self.subj.get_content() def set_content(self, content): raise PermissionError # filename = "abc.txt" # username = input() # if username!="alex": # p = ProxyC(filename) # else: # p = ProxyA(filename) # # print(p.get_content())
内容:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
角色:
例:
适用场景:
优点:
缺点:
from abc import ABCMeta, abstractmethod class Handler(metaclass=ABCMeta): @abstractmethod def handle_leave(self, day): pass class GeneralManagerHandler(Handler): def handle_leave(self, day): if day < 10: print("总经理批准%d天假" % day) return True else: print("呵呵") return False class DepartmentManagerHandler(Handler): def __init__(self): self.successor = GeneralManagerHandler() def handle_leave(self, day): if day < 7: print("部门经理批准%d天假" % day) return True else: print("部门经理无权准假") return self.successor.handle_leave(day) class ProjectDirectorHandler(Handler): def __init__(self): self.successor = DepartmentManagerHandler() def handle_leave(self, day): if day < 3: print("项目主管批准%d天假" % day) return True else: print("项目主管无权准假") return self.successor.handle_leave(day) day = 11 h = ProjectDirectorHandler() print(h.handle_leave(day))
# --高级例子--模仿js事件处理 from abc import ABCMeta, abstractmethod class Handler(metaclass=ABCMeta): @abstractmethod def add_event(self, func): pass @abstractmethod def handle(self): pass class BodyHandler(Handler): def __init__(self): self.func = None def add_event(self, func): self.func = func def handle(self): if self.func: return self.func() else: print("已到最后一级,无法处理") class ElementHandler(Handler): def __init__(self, successor): self.func = None self.successor = successor def add_event(self, func): self.func = func def handle(self): if self.func: return self.func() else: return self.successor.handle() # 客户端 # <body><div><a> body = {‘type‘: ‘body‘, ‘name‘: ‘body‘, ‘children‘: [], ‘father‘: None} div = {‘type‘: ‘div‘, ‘name‘: ‘div‘, ‘children‘: [], ‘father‘: body} a = {‘type‘: ‘a‘, ‘name‘: ‘a‘, ‘children‘: [], ‘father‘: div} body[‘children‘].append(div) div[‘children‘].append(a) # print(body) body[‘event_handler‘] = BodyHandler() div[‘event_handler‘] = ElementHandler(div[‘father‘][‘event_handler‘]) a[‘event_handler‘] = ElementHandler(a[‘father‘][‘event_handler‘]) def attach_event(element, func): element[‘event_handler‘].add_event(func) # test def func_a(): print("这是给a的函数") def func_div(): print("这是给div的函数") def func_body(): print("这是给body的函数") attach_event(a, func_a) attach_event(div, func_div) attach_event(body, func_body) a[‘event_handler‘].handle()
内容:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
适用场景:
实现方法:__iter__、__next__
class LinkList: """链表 头结点保存链表的长度""" class Node: def __init__(self, item=None): self.item = item self.next = None class LinkListIterator: def __init__(self, node): self.node = node def __next__(self): if self.node: cur_node = self.node self.node = cur_node.next return cur_node.item else: raise StopIteration def __iter__(self): return self def __init__(self, iterable=None): self.head = LinkList.Node(0) self.tail = self.head self.extend(iterable) def append(self, obj): s = LinkList.Node(obj) self.tail.next = s self.tail = s self.head.item += 1 def extend(self, iterable): for obj in iterable: self.append(obj) def __iter__(self): return self.LinkListIterator(self.head.next) def __len__(self): return self.head.item def __str__(self): return "<<" + ", ".join(map(str, self)) + ">>" li = [i for i in range(100)] lk = LinkList(li) print(lk)
内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式
角色:
适用场景:
优点:
缺点:
from abc import ABCMeta, abstractmethod class Observer(metaclass=ABCMeta): @abstractmethod def update(self, 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) # obs.company_info=None def notify(self): for obj in self.observers: obj.update(self) class ManagerNotice(Notice): def __init__(self, company_info=None): super().__init__() self.__company_info = company_info def detach(self, obs): super().detach(obs) obs.company_info = None @property def company_info(self): return self.__company_info @company_info.setter def company_info(self, info): self.__company_info = info self.notify() class Manager(Observer): def __init__(self): self.company_info = None def update(self, noti): self.company_info = noti.company_info notice = ManagerNotice() alex = Manager() wusir = Manager() print(alex.company_info) print(wusir.company_info) notice.attach(alex) notice.attach(wusir) notice.company_info = "公司运行良好" print(alex.company_info) print(wusir.company_info) notice.company_info = "公司将要上市" print(alex.company_info) print(wusir.company_info) notice.detach(wusir) notice.company_info = "公司要破产了,赶快跑路" print(alex.company_info) print(wusir.company_info) notice.company_info = "公司已经破产了" print(alex.company_info) print(wusir.company_info)
内容:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
角色:
适用场景:
优点:
缺点:
from abc import ABCMeta, abstractmethod import random class Sort(metaclass=ABCMeta): @abstractmethod def sort(self, data): pass class QuickSort(Sort): def quick_sort(self, data, left, right): if left < right: mid = self.partition(data, left, right) self.quick_sort(data, left, mid - 1) self.quick_sort(data, mid + 1, right) def partition(self, data, left, right): tmp = data[left] while left < right: while left < right and data[right] >= tmp: right -= 1 data[left] = data[right] while left < right and data[left] <= tmp: left += 1 data[right] = data[left] data[left] = tmp return left def sort(self, data): print("快速排序") return self.quick_sort(data, 0, len(data) - 1) class MergeSort(Sort): def merge(self, data, low, mid, high): i = low j = mid + 1 ltmp = [] while i <= mid and j <= high: if data[i] <= data[j]: ltmp.append(data[i]) i += 1 else: ltmp.append(data[j]) j += 1 while i <= mid: ltmp.append(data[i]) i += 1 while j <= high: ltmp.append(data[j]) j += 1 data[low:high + 1] = ltmp def merge_sort(self, data, low, high): if low < high: mid = (low + high) // 2 self.merge_sort(data, low, mid) self.merge_sort(data, mid + 1, high) self.merge(data, low, mid, high) def sort(self, data): print("归并排序") return self.merge_sort(data, 0, len(data) - 1) class Context: def __init__(self, data, strategy=None): self.data = data self.strategy = strategy def set_strategy(self, strategy): self.strategy = strategy def do_strategy(self): if self.strategy: self.strategy.sort(self.data) else: raise TypeError li = list(range(100000)) random.shuffle(li) context = Context(li, MergeSort()) context.do_strategy() # print(context.data) random.shuffle(context.data) context.set_strategy(QuickSort()) context.do_strategy()
内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:
适用场景:
from abc import ABCMeta, abstractmethod class IOHandler(metaclass=ABCMeta): @abstractmethod def open(self, name): pass @abstractmethod def deal(self, change): pass @abstractmethod def close(self): pass def process(self, name, change): self.open(name) self.deal(change) self.close() class FileHandler(IOHandler): def open(self, name): self.file = open(name, "w") def deal(self, change): self.file.write(change) def close(self): self.file.close() f = FileHandler() f.process("abc.txt", "Hello World")
《二十三种设计模式及其python实现》——李琼羽
标签:实体 general 对象创建 tar 灵活 hide 提取 ret rem
原文地址:https://www.cnblogs.com/bubu99/p/12216113.html