23种设计模式Python版
目录
- 创建型模式
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
- 单例模式
- 原型模式
- 建造者模式
- 结构型模式
- 适配器模式
- 桥接模式
- 组合模式
- 装饰器模式
- 外观模式
- 享元模式
- 代理模式
- 行为型模式
- 职责链模式
- 命令模式
- 解释器模式
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 策略模式
- 模板方法模式
- 访问者模式
- Reference
创建型模式
简单工厂模式
- 实现
from abc import abstractmethod, ABCMetaclass Product(metaclass = ABCMeta):def __init__(self):pass@abstractmethoddef do(self):passclass ConcreteProductA(Product):def __init__(self):super().__init__()def do(self):print("[ConcreteProductA]do()")class ConcreteProductB(Product):def __init__(self):super().__init__()def do(self):print("[ConcreteProductB]do()")class SimpleFactory:@staticmethoddef create_product(arg):if "A" == str.upper(arg):return ConcreteProductA()elif "B" == str.upper(arg):return ConcreteProductB()else:raise Exception(f"Unsupported: {arg}")if __name__ == "__main__":product_a = SimpleFactory.create_product("A")product_a.do()product_b = SimpleFactory.create_product("b")product_b.do()
- 优点
简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开。客户端只需提供想要的产品属性,简单工厂就可以创建出来具体的产品供客户端使用(客户端不用关心创建逻辑)。 - 缺点
工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。系统扩展困难,一旦添加新产品就得修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。 - 适用场景
工厂类负责创建的对象比较少,不会造成工厂方法中的业务逻辑太过复杂。
工厂方法模式
- 实现
from abc import abstractmethod, ABCMetaclass Product(metaclass = ABCMeta):def __init__(self):pass@abstractmethoddef do(self):passclass ConcreteProductA(Product):def __init__(self):super().__init__()def do(self):print("[ConcreteProductA]do()")class ConcreteProductB(Product):def __init__(self):super().__init__()def do(self):print("[ConcreteProductB]do()")class Factory(metaclass = ABCMeta):def __init__(self):pass@abstractmethoddef create_product(self):passclass FactoryA(Factory):def __init__(self):super().__init__()def create_product(self):return ConcreteProductA()class FactoryB(Factory):def __init__(self):super().__init__()def create_product(self):return ConcreteProductB()if __name__ == "__main__":factoryA = FactoryA()productA = factoryA.create_product()productA.do()factoryB = FactoryB()productB = factoryB.create_product()productB.do()
-
优点
继承了简单工厂模式的优点,用户只需要关心所需产品对应的工厂。扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以,符合“开闭原则”。 -
缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度。 -
使用场景
数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
抽象工厂模式
产品族:小米的手机+电视、华为的手机+电视
产品等级结构:手机的小米+华为,电视的小米+华为
增加产品族,比如OPPO的手机+电视,只需增加OPPO工厂及对应具体产品即可,符合“开闭原则”;但增加产品等级结构,比如耳机的小米+华为,就需要修改所有工厂,违反“开闭原则”。
from abc import abstractmethod, ABCMetaclass ProductA(metaclass = ABCMeta):def __init__(self):pass@abstractmethoddef do(self):passclass ConcreteProductA1(ProductA):def __init__(self):super().__init__()def do(self):print("[ConcreteProductA1]do()")class ConcreteProductA2(ProductA):def __init__(self):super().__init__()def do(self):print("[ConcreteProductA2]do()")class ProductB(metaclass = ABCMeta):def __init__(self):pass@abstractmethoddef do(self):passclass ConcreteProductB1(ProductB):def __init__(self):super().__init__()def do(self):print("[ConcreteProductB1]do()")class ConcreteProductB2(ProductB):def __init__(self):super().__init__()def do(self):print("[ConcreteProductB2]do()")class Factory(metaclass = ABCMeta):def __init__(self):pass@abstractmethoddef create_productA(self):pass@abstractmethoddef create_productB(self):passclass Factory1(Factory):def __init__(self):super().__init__()def create_productA(self):return ConcreteProductA1()def create_productB(self):return ConcreteProductB1()class Factory2(Factory):def __init__(self):super().__init__()def create_productA(self):return ConcreteProductA2()def create_productB(self):return ConcreteProductB2()if __name__ == "__main__":factory1 = Factory1()productA1 = factory1.create_productA()productB1 = factory1.create_productB()productA1.do()productB1.do()factory2 = Factory2()productA2 = factory2.create_productA()productB2 = factory2.create_productB()productA2.do()productB2.do()
单例模式
class Singleton:def __new__(cls, *args, **kwargs):if not hasattr(cls, "_instance"):cls._instance = super(Singleton, cls).__new__(cls)return cls._instanceif __name__ == "__main__":singleton1 = Singleton(1, x = 1)singleton2 = Singleton(2, x = 2)print(id(singleton1) == id(singleton2))
原型模式
浅克隆
深克隆
from abc import ABCMeta, abstractmethod
import copyclass Prototype(metaclass = ABCMeta):@abstractmethoddef clone(self):passclass PrototypeA(Prototype):def clone(self):return copy.copy(self)class PrototypeB(Prototype):def clone(self):return copy.copy(self)if __name__ == "__main__":prototypeA = PrototypeA()prototypeACopy = prototypeA.clone()
建造者模式
from abc import ABCMeta, abstractmethodclass Product:def __init__(self, a = None, b = None, c = None):self.a = aself.b = bself.c = cdef __str__(self):return f"Product[a={self.a}, b={self.b}, c={self.c}]"class Builder(metaclass = ABCMeta):@abstractmethoddef buildA(self):pass@abstractmethoddef buildB(self):pass@abstractmethoddef buildC(self):pass@abstractmethoddef getResult(self):passclass ConcreteBuilder(Builder):def __init__(self):self.product = Product()def buildA(self):self.product.a = "A"print(f"build part {self.product.a}")def buildB(self):self.product.b = "B"print(f"build part {self.product.b}")def buildC(self):self.product.c = "C"print(f"build part {self.product.c}")def getResult(self):return self.productclass Director:def __init__(self, builder):self.builder = builderdef construct(self):self.builder.buildA()self.builder.buildB()self.builder.buildC()return self.builder.getResult()if __name__ == "__main__":builder = ConcreteBuilder()director = Director(builder)product = director.construct()print(product)
结构型模式
适配器模式
我的笔记本电脑的工作电压是20V,而我国的家庭用电是220V,如何让20V的笔记本电脑能够在220V的电压下工作?答案是引入一个电源适配器(AC Adapter),俗称充电器或变压器。
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。以电源适配器(Adapter)为例,Target是电脑目前支持的22V接口,Adaptee是220V插口。
对象适配器
from abc import ABCMeta, abstractmethodclass Target(metaclass = ABCMeta):@abstractmethoddef request(self):print("can use 20V")class Adaptee:def specificRequest(self):print("can use 220V")class Adapter(Target):def __init__(self):self.adaptee = Adaptee()def request(self):print("Before")super().request()print()print("Now")print(f"Adapter, converting from 20V to 220V, ... , done")self.adaptee.specificRequest()if __name__ == "__main__":adapter = Adapter()adapter.request()
类适配器
from abc import ABCMeta, abstractmethodclass Target(metaclass = ABCMeta):@abstractmethoddef request(self):print("can use 20V")class Adaptee:def specificRequest(self):print("can use 220V")class Adapter(Target, Adaptee):def request(self):print("Before")super().request()print()print("Now")print(f"Adapter, converting from 20V to 220V, ... , done")self.specificRequest() # super().specificRequest()if __name__ == "__main__":adapter = Adapter()adapter.request()
桥接模式
将一个事物的两个维度分离,使其都可以独立地变化。
from abc import ABCMeta, abstractmethodclass Shape(metaclass = ABCMeta):def __init__(self, color):self.color = color@abstractmethoddef draw(self):passclass Rectangle(Shape):def draw(self):self.shape_name = "rectangle"self.color.paint()print(f"draw a {self.color.color_name} {self.shape_name}")class Circle(Shape):def draw(self):self.shape_name = "circle"self.color.paint()print(f"draw a {self.color.color_name} {self.shape_name}")class Color(metaclass = ABCMeta):@abstractmethoddef paint(self):passclass Red(Color):def paint(self):self.color_name = "red"class Blue(Color):def paint(self):self.color_name = "blue"if __name__ == "__main__":shape = Circle(Red())shape.draw()
组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
from abc import ABCMeta, abstractmethodclass AbstractFile(metaclass = ABCMeta):@abstractmethoddef add(self, file):pass@abstractmethoddef remove(self, file):pass@abstractmethoddef getChild(self, i):pass@abstractmethoddef traverse(self, deep):passclass TextFile(AbstractFile):def __init__(self, name):self.name = namedef add(self, file):raise Exception("unsupported")def remove(self, file):raise Exception("unsupported")def getChild(self, i):raise Exception("unsupported")def traverse(self, deep):for i in range(deep):print("\t", end="")print(f"text:{self.name}")class ImageFile(AbstractFile):def __init__(self, name):self.name = namedef add(self, file):raise Exception("unsupported")def remove(self, file):raise Exception("unsupported")def getChild(self, i):raise Exception("unsupported")def traverse(self, deep):for i in range(deep):print("\t", end="")print(f"image:{self.name}")class Folder(AbstractFile):def __init__(self, name):self.name = nameself.file_list = []def add(self, file):self.file_list.append(file)def remove(self, file):self.file_list.remove(file)def getChild(self, i):return self.file_list.index(i)def traverse(self, deep):for i in range(deep):print("\t", end="")print(self.name)for f in self.file_list:f.traverse(deep + 1)if __name__ == "__main__":folder1 = Folder("folder1")file1 = TextFile("t1.txt")file2 = ImageFile("i1.png")folder1.add(file1)folder1.add(file2)folder2 = Folder("folder2")file3 = TextFile("t2.txt")file4 = ImageFile("i2.png")folder2.add(file3)folder2.add(file4)folder1.add(folder2)folder1.traverse(0)
装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。它是作为现有的类的一个包装。
from abc import ABCMeta, abstractmethodclass Component(metaclass = ABCMeta):@abstractmethoddef operation(self):passclass ConcreteComponent(Component):def operation(self):print("ConcreteComponent.operation()")class Decorator(Component):def __init__(self, component):self.component = componentdef operation(self):self.component.operation()class ConcreteDecoratorA(Decorator):def __init__(self, component, state):super().__init__(component)self.state = statedef operation(self):super().operation()print(f"state: {self.state}")class ConcreteDecoratorB(Decorator):def operation(self):super().operation()self.added_behavior()def added_behavior(self):print("ConcreteDecoratorB.added_behavior()")if __name__ == "__main__":component = ConcreteComponent()decoratorA = ConcreteDecoratorA(component, "Normal")decoratorA.operation()decoratorB = ConcreteDecoratorB(component)decoratorB.operation()
外观模式
外观模式中,一个子系统的外部与其内部的通信通过一个统一的外观类进行,外观类将客户类与子系统的内部复杂性分隔开,使得客户类只需要与外观角色打交道,而不需要与子系统内部的很多对象打交道。
class CPU:def start(self):print("cpu start...")def stop(self):print("cpu stop...")class Memory:def start(self):print("memory start...")def stop(self):print("memory stop...")class Disk:def start(self):print("disk start...")def stop(self):print("disk stop...")class Computer:def __init__(self):self.cpu = CPU()self.memory = Memory()self.disk = Disk()def start(self):self.cpu.start()self.memory.start()self.disk.start()def stop(self):self.cpu.stop()self.memory.stop()self.disk.stop()if __name__ == "__main__":computer = Computer()computer.start()computer.stop()
享元模式
围棋棋子只有黑白棋两种(内部状态只有黑白,所有黑子共享黑内部状态,所有白子共享白内部状态。减少创建对象的数量),而每次落子坐标不同(外部状态)。
from abc import abstractmethod, ABCMetaclass IgoChessman(metaclass = ABCMeta):@abstractmethoddef get_color(self):passdef display(self, coordinate):print(f"{self.get_color()}, {coordinate.x, coordinate.y}")class BlackIgoChessman(IgoChessman):def get_color(self):return "black"class WhiteIgoChessman(IgoChessman):def get_color(self):return "white"class IgoChessmanFactory:def __new__(cls, *args, **kwargs):if not hasattr(cls, "_instance"):cls._instance = super(IgoChessmanFactory, cls).__new__(cls)cls._instance.ht = {}cls._instance.ht["black"] = BlackIgoChessman()cls._instance.ht["white"] = WhiteIgoChessman()return cls._instancedef getIgoChessman(self, color):return IgoChessmanFactory._instance.ht[color]class Coordinate:def __init__(self, x, y):self.x = xself.y = yif __name__ == "__main__":factory = IgoChessmanFactory()black1 = factory.getIgoChessman("black")white1 = factory.getIgoChessman("white")black2 = factory.getIgoChessman("black")white2 = factory.getIgoChessman("white")print(black1 is black2)print(white1 is white2)black1.display(Coordinate(1, 2))white1.display(Coordinate(3, 4))black2.display(Coordinate(8, 9))white2.display(Coordinate(4, 5))
代理模式
保护代理(Protect Proxy):控制对一个对象的访问,给不同的用户提供不同级别的使用权限。
from abc import abstractmethod, ABCMeta
import timeclass Searcher(metaclass = ABCMeta):@abstractmethoddef search(self, user_id, key_word):passclass RealSearcher(Searcher):def search(self, user_id, key_word):print(f"[RealSearcher.search](use_id: {user_id}, key_word: {key_word}) and return 'what you want'")class AccessValidator:def validate(self, user_id):print(f"[AccessValidator.validate]{user_id} has access to search!")class Logger:def log(self, user_id):print(f"[Logger.log]{user_id} visit at {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))}")class ProxySearcher(Searcher):def __init__(self):self.validator = AccessValidator()self.logger = Logger()self.searcher = RealSearcher()def search(self, user_id, key_word):self.validator.validate(user_id)self.searcher.search(user_id, key_word)self.logger.log(user_id)if __name__ == "__main__":proxy = ProxySearcher()proxy.search("Tom", "iPhone")
行为型模式
职责链模式
职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
from abc import abstractmethod, ABCMetaclass Handler(metaclass = ABCMeta):@abstractmethoddef handle_leave(self, day):passdef set_successor(self, successor):self.successor = successorclass GeneralManagerHandler(Handler):def handle_leave(self, day):if day <= 10:print("General manager approved %d days' leave." % day)else:print("No approval!")class DepartmentManagerHandler(Handler):def handle_leave(self, day):if day <= 7:print("Department manager approved %d days' leave." % day)else:self.successor.handle_leave(day)class ProjectManagerHandler(Handler):def handle_leave(self, day):if day <= 3:print("Project manager approved %d days' leave." % day)else:self.successor.handle_leave(day)if __name__ == "__main__":projectManager = ProjectManagerHandler()departmentManager = DepartmentManagerHandler()generalManager = GeneralManagerHandler()projectManager.set_successor(departmentManager)departmentManager.set_successor(generalManager)projectManager.handle_leave(8)
命令模式
Invoker:开关
Command:电线
Receiver:电灯/排风扇
命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。
from abc import abstractmethod, ABCMetaclass Invoker:def __init__(self, wire):self.wire = wiredef open(self):self.wire.execute()class Wire(metaclass = ABCMeta):@abstractmethoddef execute(self):passclass LampWire(Wire):def __init__(self):self.lamp_receiver = LampReceiver()def execute(self):self.lamp_receiver.action()class FanWire(Wire):def __init__(self):self.fan_wire = FanReceiver()def execute(self):self.fan_wire.do()class LampReceiver:def action(self):print("open the lamp")class FanReceiver:def do(self):print("open the fan") if __name__ == "__main__":invoker1 = Invoker(LampWire())invoker1.open()invoker2 = Invoker(FanWire())invoker2.open()
解释器模式
简化版四则运算解释器的实现(真正实现要搞定中缀表达式求解逻辑,封入Context中)
from abc import abstractmethod, ABCMetaclass Expression(metaclass = ABCMeta):@abstractmethoddef interpret(self, context):passclass NumberExpression(Expression):def __init__(self, value):self.value = valuedef interpret(self, context):return self.valueclass AddExpression(Expression):def __init__(self, left, right):self.left = leftself.right = rightdef interpret(self, context):return self.left.interpret(context) + self.right.interpret(context)class SubtractExpression(Expression):def __init__(self, left, right):self.left = leftself.right = rightdef interpret(self, context):return self.left.interpret(context) - self.right.interpret(context)class Context:passif __name__ == '__main__':expression = AddExpression(NumberExpression(10), SubtractExpression(NumberExpression(5), NumberExpression(2)))result = expression.interpret(Context())print(result)
迭代器模式
在软件开发中,我们经常需要使用聚合对象来存储一系列数据。聚合对象拥有两个职责:一是存储数据;二是遍历数据。从依赖性来看,前者是聚合对象的基本职责;而后者既是可变化的,又是可分离的。因此,可以将遍历数据的行为从聚合对象中分离出来,封装在一个被称之为“迭代器”的对象中,由迭代器来提供遍历聚合对象内部数据的行为,这将简化聚合对象的设计,更符合“单一职责原则”的要求。
迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
在迭代器模式结构中包含聚合和迭代器两个层次结构,考虑到系统的灵活性和可扩展性,在迭代器模式中应用了工厂方法模式,其模式结构如下图所示:
from abc import ABC, abstractmethodclass Aggregate(ABC):@abstractmethoddef create_iterator(self):passclass ConcreteAggregate(Aggregate):def __init__(self):self.data = list(range(1, 6))self.idx = 0def create_iterator(self):return ConcreteIterator(self)class Iterator(ABC):@abstractmethoddef has_next(self):pass@abstractmethoddef next(self):passclass ConcreteIterator(Iterator):def __init__(self, aggregate):self.aggregate = aggregatedef has_next(self):return self.aggregate.idx < len(self.aggregate.data)def next(self):data = self.aggregate.data[self.aggregate.idx]self.aggregate.idx += 1return dataif __name__ == '__main__':aggregate = ConcreteAggregate()iterator = aggregate.create_iterator()while iterator.has_next():print(iterator.next())
中介者模式
如果在一个系统中对象之间存在多对多的相互关系,我们可以将对象之间的一些交互行为从各个对象中分离出来,并集中封装在一个中介者对象中,并由该中介者进行统一协调,这样对象之间多对多的复杂关系就转化为相对简单的一对多关系。通过引入中介者来简化对象之间的复杂交互,中介者模式是“迪米特法则”的一个典型应用。
以微信群发消息为例(多人两两交互变为一对多交互),实现如下:
from abc import ABC, abstractmethodclass Mediator(ABC):@abstractmethoddef send_msg(self, colleague, msg):passclass ConcreteMediator(Mediator):def send_msg(self, colleague, msg):print(f"[{colleague.name}] {msg}")class Colleague(ABC):@abstractmethoddef __init__(self, name, mediator):self.mediator = mediatorself.name = name@abstractmethoddef send_msg(self, msg):pass class ConcreteColleague(Colleague):def __init__(self, name, mediator):super().__init__(name, mediator)def send_msg(self, msg):self.mediator.send_msg(self, msg)if __name__ == '__main__':mediator = ConcreteMediator()colleague1 = ConcreteColleague("Jack", mediator)colleague2 = ConcreteColleague("Marry", mediator)colleague1.send_msg("Are you ok")colleague2.send_msg("Happy")
备忘录模式
备忘录模式提供了状态恢复机制,比如下棋的悔棋就可以用备忘录模式实现。
class Chessman:def __init__(self, label, x, y):self.label = labelself.x = xself.y = ydef set_x(self, x):self.x = xdef set_y(self, y):self.y = ydef display(self):print(f"[{self.label}] x = {self.x}, y = {self.y}")def save(self):return Memo(self.label, self.x, self.y)def restore(self, memo):self.label = memo.labelself.x = memo.xself.y = memo.yclass Memo:def __init__(self, label, x, y):self.label = labelself.x = xself.y = yclass MemoManager:def __init__(self):self.memos = []def add_memo(self, memo):self.memos.append(memo)def pop_memo(self):print("Try to undo...")if(len(self.memos) < 1):print("The location now is original, so you cannot undo!")return Nonereturn self.memos.pop()if __name__ == '__main__':manager = MemoManager()chessman = Chessman('CAR', 1, 1)chessman.display()memo = chessman.save()manager.add_memo(memo)chessman.set_y(4)chessman.display()memo = chessman.save()manager.add_memo(memo)chessman.set_x(6)chessman.display()memo = manager.pop_memo()if memo is not None:chessman.restore(memo)chessman.display()memo = manager.pop_memo()if memo is not None:chessman.restore(memo)chessman.display()memo = manager.pop_memo()if memo is not None:chessman.restore(memo)chessman.display()
观察者模式
“红灯停,绿灯行”,在日常生活中,交通信号灯装点着我们的城市,指挥着日益拥挤的城市交通。当红灯亮起,来往的汽车将停止;而绿灯亮起,汽车可以继续前行。在这个过程中,交通信号灯是汽车(更准确地说应该是汽车驾驶员)的观察目标,而汽车是观察者。随着交通信号灯的变化,汽车的行为也将随之而变化,一盏交通信号灯可以指挥多辆汽车。
观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
from abc import ABC, abstractmethodclass Observer(ABC):def __init__(self, name):self.name = name@abstractmethoddef update(msg):passclass ConcreteObserver(Observer):def __init__(self, name):super().__init__(name)def update(self, msg):print(f"[{self.name}]: {msg}")class Project(ABC):@abstractmethoddef add_observer(self, observer):pass@abstractmethoddef delete_observer(self, observer):pass@abstractmethoddef notify(self):passclass ConcreteProject(Project):def __init__(self):self.observers = []def add_observer(self, observer):self.observers.append(observer)def delete_observer(self, observer):self.observers.remove(observer)def notify(self, msg):for observer in self.observers:observer.update(msg)if __name__ == '__main__':traffic_light = ConcreteProject()tom = ConcreteObserver("Tom")lucy = ConcreteObserver("Lucy")traffic_light.add_observer(tom)traffic_light.add_observer(lucy)traffic_light.notify("traffic light is red")
状态模式
点击循环调整屏幕尺寸,正常、更大、最大、正常……
from abc import ABC, abstractmethodclass State(ABC):@abstractmethoddef display(self):passclass NormalState(State):def display(self):print("Normal")class LargerState(State):def display(self):print("Larger")class LargestState(State):def display(self):print("Largest")class Screen:def __init__(self):self.normal_state = NormalState()self.larger_state = LargerState()self.largest_state = LargestState()self.state = self.normal_statedef on_click(self):if self.state is self.normal_state:self.state = self.larger_stateelif self.state is self.larger_state:self.state = self.largest_stateelse:self.state = self.normal_stateself.state.display()if __name__ == '__main__':screen = Screen()screen.on_click()screen.on_click()screen.on_click()screen.on_click()
策略模式
from abc import ABC, abstractmethodclass Strategy(ABC):@abstractmethoddef algorithm(self):passclass ConcreteStategyA(Strategy):def algorithm(self):print("ConcreteStategyA")class ConcreteStategyB(Strategy):def algorithm(self):print("ConcreteStategyB")class Context:def set_stategy(self, strategy):self.strategy = strategydef algorithm(self):self.strategy.algorithm()if __name__ == '__main__':context = Context()context.set_stategy(ConcreteStategyA())context.algorithm()context.set_stategy(ConcreteStategyB())context.algorithm()
模板方法模式
from abc import ABC, abstractmethodclass Game(ABC):def play(self):self.init()self.start()self.end()@abstractmethoddef init(self):pass@abstractmethoddef start(self):pass@abstractmethoddef end(self):passclass GameA(Game):def init(self):print("[GameA]init...")def start(self):print("[GameA]start...")def end(self):print("[GameA]end...")class GameB(Game):def init(self):print("[GameB]init...")def start(self):print("[GameB]start...")def end(self):print("[GameB]end...")if __name__ == '__main__':game_a = GameA()game_a.play()game_b = GameB()game_b.play()
访问者模式
访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。例如处方单中的各种药品信息就是被访问的元素,而划价人员和药房工作人员就是访问者。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。
公司中有正式工和临时工,而HR和财务人员对工人的关注点不同,前者关心工时计算,后者关心工资计算。这个例子中,工人对应Element,HR和财务人员对应Visitor。实现如下:
from abc import ABC, abstractmethodclass Employee(ABC):@abstractmethoddef accept(self, handler):passclass FulltimeEmployee(Employee):def __init__(self, name, weekly_wage, work_time):self.name = nameself.weekly_wage = weekly_wageself.work_time = work_timedef accept(self, handler):handler.visit_fulltime_employee(self)class ParttimeEmployee(Employee):def __init__(self, name, hourly_wage, work_time):self.name = nameself.hourly_wage = hourly_wageself.work_time = work_timedef accept(self, handler):handler.visit_parttime_employee(self)class Department(ABC):@abstractmethoddef visit_fulltime_employee(self, employee):pass@abstractmethoddef visit_parttime_employee(self, employee):passclass FinanceDepartment(Department):def visit_fulltime_employee(self, employee):if(employee.work_time > 40):week_wage = employee.weekly_wage + (employee.work_time - 40) * 100else:week_wage = employee.weekly_wage - (40 - employee.work_time) * 80if week_wage < 0:week_wage = 0print(f"Fulltime employee {employee.name}, salary = {week_wage} yuan")def visit_parttime_employee(self, employee):print(f"Parttime employee {employee.name}, salary = {employee.work_time * employee.hourly_wage} yuan")class HRDepartment(Department):def visit_fulltime_employee(self, employee):print(f"Fulltime employee {employee.name}, work time = {employee.work_time} hours")if(employee.work_time > 40):print(f"Fulltime employee {employee.name}, overtime = {employee.work_time - 40} hours")else:print(f"Fulltime employee {employee.name}, vocation time = {40 - employee.work_time} hours")def visit_parttime_employee(self, employee):print(f"Parttime employee {employee.name}, work time = {employee.work_time} hours")class EmployeeList:def __init__(self):self.employees = []def add(self, employee):self.employees.append(employee)def accept(self, handler):for employee in self.employees:employee.accept(handler)if __name__ == '__main__':employee_list = EmployeeList()employee1 = FulltimeEmployee("employee1", 1000, 30)employee2 = FulltimeEmployee("employee2", 3000, 50)employee3 = ParttimeEmployee("employee3", 30, 15)employee4 = ParttimeEmployee("employee4", 20, 10)employee_list.add(employee1)employee_list.add(employee2)employee_list.add(employee3)employee_list.add(employee4)department1 = HRDepartment()department2 = FinanceDepartment()employee_list.accept(department1)employee_list.accept(department2)
Reference
[1] 史上最全设计模式导学目录(完整版)
相关文章:
23种设计模式Python版
目录 创建型模式简单工厂模式工厂方法模式抽象工厂模式单例模式原型模式建造者模式 结构型模式适配器模式桥接模式组合模式装饰器模式外观模式享元模式代理模式 行为型模式职责链模式命令模式解释器模式迭代器模式中介者模式备忘录模式观察者模式状态模式策略模式模板方法模式访…...
2024年汉字小达人区级选拔备考——真题做一做:诗词连线
前面,六分成长介绍了汉字小达人区级选拔样题的第一大题看拼音写汉字,以及第二大题补充成语。这两道题都是填空题,通常在学校进行线下选拔的时候使用。这篇文章介绍第三大题:诗词连线。 诗词连线是2022年(第九届&#x…...
Vite scss 如何引入本地 字体
Vite scss 如何引入本地 字体 最近在用 Vite 改造一个旧项目 Diary,遇到了好多从 Vue 转到 Vite 的问题。 这次这个问题是: scss 里本地字体引入的问题。 一、问题描述 可以看到下面的卡片字体,本来应该是 impact 的,但现在无法…...
扩展 apiserver 连接认证 ip, apiserver证书更新
本文来自我的博客地址 文章目录 问题场景:问题分析:问题解决:查看 apiserver 证书支持的 ip 或 host使用 openssl 生成证书:再次查看 apiserver 证书支持的 ip 或 host 再次尝试将 master 加点加入参考 问题场景: k8s 1.28.1 集群后期新增 vip apiserver 证书不支持 vip 引入…...
VUE--保留小数(过滤器)
1.cutOutNum.js export const cutOutNum (num, decimals) > {if (isNaN(num) || (!num && num ! 0)) {return "-";}function toNonExponential(_num) {var m Number(_num).toExponential().match(/\d(?:\.(\d*))?e([-]\d)/);return Number(_num).toF…...
书生·浦语大模型实战营第一次课堂笔记
书生浦语大模型全链路开源体系。大模型是发展通用人工智能的重要途径,是人工通用人工智能的一个重要途径。书生浦语大模型覆盖轻量级、重量级、重量级的三种不同大小模型,可用于智能客服、个人助手等领域。还介绍了书生浦语大模型的性能在多个数据集上全面超过了相似量级或相近…...
Mysql为什么只能支持2000w左右的数据量?
首先说明一下: MySQL并没有硬性规定只能支持到2000万左右的数据量。 其实,MySQL能够处理的数据量远远超过这个数字。无论是开源社区版还是商业版, MySQL在适当的硬件和配置下,都能够支持非常大的数据集。 通常所说的“MySQL只能…...
限制选中指定个数CheckBox控件(1/2)
限制选中指定个数CheckBox控件(1/2) 实例需求:工作表中有8个CheckBox控件(下文中简称为控件),现在需要实现限制用户最多只能勾选4个控件。 Dim OnDic As Object Sub CheckboxeEvent()Dim oCB As CheckBox…...
QT中的信号与槽的讲解
文章目录 信号及其特点槽及其特点代码演示标准信号与标准槽函数方式一方式二 自定义信号和槽connect()函数信号和槽函数存在函数重载的情况下Qt的信号槽机制注意事项 信号及其特点 信号:是一种特殊的函数,又称信号函数,俗称信号,…...
RNN文本分类任务实战
递归神经网络 (RNN): 定义:RNN 是一类专为顺序数据处理而设计的人工神经网络。 顺序处理:RNN 保持一个隐藏状态,该状态捕获有关序列中先前输入的信息,使其适用于涉及顺序依赖关系的任务。词嵌入…...
【算法系列 | 12】深入解析查找算法之—斐波那契查找
序言 心若有阳光,你便会看见这个世界有那么多美好值得期待和向往。 决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。 我们一起努力,成为更好的自己! 今天第12讲,讲…...
全新的C++语言
一、概述 C 的最初目标就是成为 “更好的 C”,因此新的标准首先要对基本的底层编程进行强化,能够反映当前计算机软硬件系统的最新发展和变化(例如多线程)。另一方面,C对多线程范式的支持增加了语言的复杂度࿰…...
three.js 多通道组合
效果: 代码: <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div style"border: 1px so…...
编程笔记 html5cssjs 022 HTML表单概要
编程笔记 html5&css&js 022 HTML表单概要 一、<form> 元素二、HTML Form 属性三、操作小结 网页光是输出没有输入可不行,因为输出还是比输入容易,所有就先接触输出,后学习输入。html用来输入的东西叫“表单”。 HTML 表单用于搜…...
三子棋(c语言)
前言: 三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏规则是双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利。但因棋盘太小,三子棋在很多时候会出现和…...
MySQL-DCL
DCL是数据控制语言,用来管理数据库用户,控制数据库的访问权限。 管理用户:管理哪些用户可以访问哪些数据库 1.查询用户 USE mysql; SELECT * FROM user; 注意: MySQL中用户信息和用户的权限信息都是记录在mysql数据库的user表中的…...
QT开源类库集合
QT开源类库集合 一、自定义控件 QSintQicsTableLongscroll-qtAdvanced Docking System 二、图表控件 QwtQCustomPlotJKQTPlotter 三、网络 QHttpEngineHTTP 四、 音视频 vlc-qt 五、多线程 tasks 六、数据库 EasyQtSql 一、自定义控件 1. QSint 源代码地址:QSint&…...
C++ STL(2)--算法(2)
算法(2)----STL里的排序函数。 1. sort: 对容器或普通数组中指定范围内的元素进行排序,默认进行升序排序。 sort函数是基于快速排序实现的,属于不稳定排序。 只支持3种容器:array、vector、deque。 如果容器中存储的是自定义的对象ÿ…...
格密码基础:对偶格(超全面)
目录 一. 对偶格的格点 1.1 基本定义 1.2 对偶格的例子 1.3 对偶格的图形理解 二. 对偶格的格基 2.1 基本定义 2.2 对偶格的格基证明 三. 对偶格的行列式 3.1 满秩格 3.2 非满秩格 四. 重复对偶格 五. 对偶格的转移定理(transference theoremÿ…...
ECMAScript简介及特性
ECMAScript是一种由ECMA国际(前身为欧洲计算机制造商协会)制定和发布的脚本语言规范,JavaScript在它基础上进行了自己的封装。ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现。 ECMAScript的…...
csdn中的资源文件如何删除?
csdn中的资源文件如何删除? 然后写文章的时候 点击资源绑定,解锁资源,就可以再次上传。...
NA原理及配置
在IP地址空间中,a;b;c类地址中各有一部分地址,被称为私有IP地址(私网地址),其余的为公有IP地址(公网地址) A:10.0.0.0 - 10.255.255.255 --- 相当于1条A类网段…...
解决:TypeError: ‘tuple’ object does not support item assignment
解决:TypeError: ‘tuple’ object does not support item assignment 文章目录 解决:TypeError: tuple object does not support item assignment背景报错问题报错翻译报错位置代码报错原因解决方法方法一:方法二:今天的分享就到…...
vue3项目中axios的常见用法和封装拦截(详细解释)
1、axios的简单介绍 Axios是一个基于Promise的HTTP客户端库,用于浏览器和Node.js环境中发送HTTP请求。它提供了一种简单、易用且功能丰富的方式来与后端服务器进行通信。能够发送常见的HTTP请求,并获得服务端返回的数据。 此外,Axios还提供…...
基础语法(一)(1)
常量和表达式 在这里,我们可以把Python当成一个计算器,来进行一些算术运算 例如: print(1 2 - 3) print(1 2 * 3) print(1 2 / 3)注意: print是一个python内置的函数,这个稍后我们会进行介绍 可以使用-*/&…...
YOLOv8模型yaml结构图理解(逐层分析)
前言 YOLO-V8(官网地址):https://github.com/ultralytics/ultralytics 一、yolov8配置yaml文件 YOLOv8的配置文件定义了模型的关键参数和结构,包括类别数、模型尺寸、骨架(backbone)和头部(hea…...
【大数据】Zookeeper 集群及其选举机制
Zookeeper 集群及其选举机制 1.安装 Zookeeper 集群2.如何选取 Leader 1.安装 Zookeeper 集群 我们之前说了,Zookeeper 集群是由一个领导者(Leader)和多个追随者(Follower)组成,但这个领导者是怎么选出来的…...
Redis 过期策略
我们在set key的时候可以设置key的过期时间,哪redis是怎么处理过期的key的呢? 有三种过期策略 定时过期:每个设置过期时间的key会创建一个定时器,到过期时间就会立即对key进行清除。该策略可以立即清除过期的数据,对…...
RT_Thread 调试笔记:串口打印、MSH控制台 相关
说明:记录日常使用 RT_Thread 开发时做的笔记。 持续更新中,欢迎收藏。 1.打印相关 1.打印宏定义,可以打印打印所在文件,函数,行数。 #define PRINT_TRACE() printf("-------%s:%s:%d------\r\n", __FIL…...
(适趣AI)Vue笔试题
📑前言 本文主要是【Vue】——(适趣AI)Vue笔试题的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 …...
大型电商网站开发价格/热搜榜排名前十
SVM算法比较复杂,数学功底要求很高。 详见七月大神博客《 支持向量机通俗导论(理解SVM的三层境界)》转载于:https://www.cnblogs.com/ahu-lichang/p/7181773.html...
哪里找专业做网站的人常熟/找个免费的网站
2019独角兽企业重金招聘Python工程师标准>>> 1 集操作 定义:把多个sql的结果集,通过逻辑上的整合运算,拼在一起显示。 集操作缺省下都是按第一个查询的第一列升序排序,当然除了union all: …...
wordpress类开源网站/武汉网络广告推广服务
1.设置我们的路由配置文件(/src/router/index.js): {path:*,component:Error }这里的path:’*’就是找不到页面时的配置,component是我们新建的一个Error.vue的文件。2.新建404页面: <template><div><h…...
兴仁企业建站公司/谷歌手机版下载安装
01. ip address show/ip a 检查网卡地址配置02. ping 测试网络连通性03. nmtui 图形界面修改网卡地址信息04. exit 注销05. shutdown 关机命令shutdown -h 5 指定关机时间 (推荐)shutdown -r 5 重启主机时间 (推荐)shutdown -…...
安陆 网站建设/网站seo优化案例
条件:1八位数;2.以领开头;3.末尾要依次递增 <script type"text/javascript">function Account(num,a){ // num以领开头的8位数,a依次递增 //初始的a为数字var s a.toString(); // 数字转字符串var b s.…...
丹东网站推广/扬州seo优化
6月19日,计算机科学与技术学院安弈棋社通过线上比赛的形式举办了海报设计大赛。此次活动由社团负责人郭然主持举办,社团骨干成员以及在到梦空间报名的所有同学参加。活动伊始,同学们首先进入此次活动的QQ群,安弈棋社的活动负责人在…...