Design Patterns @ Python – 23種設計模式摘要整理

The Summary for 23 Kinds of Software Design in Pattern

  • 這其實是拜託 Claud AI 請祂幫忙整理的 Summary 及代表範例,作為這個 Udemy Design Pattern in Python 課程系列筆記的總結。題外話,這次嘗試讓 AI 幫忙整理產生這麼長的摘要過程其實還蠻有趣的,每個範例還得實際跑一跑,以避免 AI 的幻覺問題影響到正確性~

1. 抽象工廠:

* 特點: 提供 Shape 家族的工廠介面來生成相關的對象

import abc

class AbstractFactory(abc.ABC):
    @abc.abstractmethod
    def create_product_a(self):
        pass

    @abc.abstractmethod
    def create_product_b(self):
        pass

class ConcreteFactory1(AbstractFactory):
    def create_product_a(self):
        return ConcreteProductA1()

    def create_product_b(self):
        return ConcreteProductB1()

class ConcreteFactory2(AbstractFactory):
    def create_product_a(self):
        return ConcreteProductA2()

    def create_product_b(self):
        return ConcreteProductB2()

class AbstractProductA(abc.ABC):
    """系列A產品介面"""

class ConcreteProductA1(AbstractProductA):
    """系列A的第1種產品實現"""

class ConcreteProductA2(AbstractProductA):
    """系列A的第2種產品實現"""
    
class AbstractProductB(abc.ABC):
    """系列B產品介面"""
    
class ConcreteProductB1(AbstractProductB):
    """系列B的第1種產品實現"""
    
class ConcreteProductB2(AbstractProductB):
    """系列B的第2種產品實現"""

2. 建造者(Builder) :

* 封裝複雜對象的建構過程,將内部表象與產品分離。

class Builder:
    def build_part_a(self):
        pass

    def build_part_b(self):
        pass

    def build_part_c(self):
        pass

class ConcreteBuilder(Builder):
    def __init__(self):
        self.product = Product()

    def build_part_a(self):
        self.product.add("PartA")

    def build_part_b(self):     
        self.product.add("PartB")

    def build_part_c(self):
        self.product.add("PartC")

    def get_result(self):
        return self.product

class Product:
    def __init__(self):
        self.parts = []

    def add(self, part):
        self.parts.append(part)

builder = ConcreteBuilder()
builder.build_part_a() 
builder.build_part_b()
builder.get_result() # 傳回 Product

3. 工廠方法(Factory Method):

* 將實例化操作推遲到子類別中進行~

import abc

class Creator(abc.ABC):
    @abc.abstractmethod
    def factory_method(self):
        pass

    def operate(self):
        product = self.factory_method()
        result = f"Creator operates with {product}" 
        return result

class ConcreteCreator(Creator):
    def factory_method(self):
        return ConcreteProduct()

class Product(abc.ABC):
    pass

class ConcreteProduct(Product): 
    pass

creator = ConcreteCreator()
creator.operate()

4. 原型(Prototype):

* 用原型實例指定要建立物件的種類,並複製這些物件~

import copy

class Prototype:
    def __init__(self):
        self._objects = {}

    def register(self, name, obj):
        self._objects[name] = obj

    def unregister(self, name):
        del self._objects[name]

    def clone(self, name, **attr):
        obj = copy.deepcopy(self._objects.get(name))
        obj.__dict__.update(attr)
        return obj

class ConcretePrototype1:
    def __init__(self):
        self.x = 10
        self.y = 20

prototype = Prototype() 
prototype.register('q1', ConcretePrototype1())
prototype.clone('q1', x=100, y=200)

5. 單例(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]

class Logger(metaclass=Singleton):
    pass

logger1 = Logger()
logger2 = Logger()
logger1 is logger2 # True

6. 適配器(Adapter):

* 將一個類別的介面轉換成客戶期望的另一個介面。

class Target:
    """目標介面"""

    def request(self):
        return "Target: 特定請求"

class Adaptee:
    """被適配的類"""

    def specific_request(self):
        return ".eetpadA :求請特定"

class Adapter(Target):
    """適配器"""

    def __init__(self, adaptee):
        self.adaptee = adaptee

    def request(self):
        return f"Adapter: {self.adaptee.specific_request()[::-1]}"

target = Target()
adaptee = Adaptee() 
adapter = Adapter(adaptee)

target.request()
adapter.request()

7. 橋接(Bridge):

* 將抽象部分與它的具體實現分離,使得二者可以獨立變化 。

class Abstraction:
    def __init__(self, implementation):
        self.implementation = implementation

    def operation(self):
        return (f"Abstraction: Base operation with:\n"
                f"{self.implementation.operation_implementation()}")

class ExtendedAbstraction(Abstraction):
    def operation(self):
        return (f"ExtendedAbstraction: Extended operation with:\n"
                f"{self.implementation.operation_implementation()}")

class Implementation:
    def operation_implementation(self):
        pass

class ConcreteImplementationA(Implementation):
    def operation_implementation(self):
        return "ConcreteImplementationA: Here's the result on the platform A."

class ConcreteImplementationB(Implementation):
    def operation_implementation(self):
        return "ConcreteImplementationB: Here's the result on the platform B."
        
abstraction = ExtendedAbstraction(ConcreteImplementationA())
abstraction.operation()

8. 組合(Composite):

* 將對象組合成樹狀結構來表達"部分-整體"的層次結構。

class Component:
    def operation(self):
        pass

class Leaf(Component):
    def operation(self):
        return "Leaf"

class Composite(Component):
    def __init__(self):
        self.children = [] 

    def add(self, component):
        self.children.append(component)

    def remove(self, component):
        self.children.remove(component)

    def operation(self):
        results = []
        for child in self.children:
            results.append(child.operation())
        return f"Branch({'+'.join(results)})"

# 用法
simple = Leaf()
tree = Composite()
tree.add(Leaf())
tree.add(Leaf())
tree.operation()

9. 裝飾(Decorator):

* 為對象動態加入行為,而不影響其他對象。

class Component:
    def operation(self):
        pass

class ConcreteComponent(Component):
    def operation(self):
        return "ConcreteComponent"

class Decorator(Component):
    def __init__(self, component):
        self._component = component

    @property
    def component(self):
        return self._component

    def operation(self):
        return self._component.operation() 

class ConcreteDecoratorA(Decorator):    
    def operation(self):
        return f"ConcreteDecoratorA({self.component.operation()})"

class ConcreteDecoratorB(Decorator):   
    def operation(self):
        return f"ConcreteDecoratorB({self.component.operation()})"

# 用法 
simple = ConcreteComponent()
decorator1 = ConcreteDecoratorA(simple)
decorator2 = ConcreteDecoratorB(decorator1)
decorator2.operation()

10. 外觀(Facade):

* 提供一個統一的介面,用來訪問子系統中的一群介面。

class Subsystem1:
    """子系統類"""
    def operation1(self):
        return "Subsystem1: Ready!"

    # ...

class Subsystem2:
    """子系統類"""
    def operation1(self): 
        return "Subsystem2: Get ready!"
    
    # ...

class Subsystem3:
    """子系統類"""
    def operation1(self):
        return "Subsystem3: Fire!"

    # ...

class Facade:
    """外觀類"""

    def __init__(self):
        self.sub1 = Subsystem1()
        self.sub2 = Subsystem2()
        self.sub3 = Subsystem3()

    def operation(self):
        results = []
        results.append(self.sub1.operation1())
        results.append(self.sub2.operation1()) 
        results.append(self.sub3.operation1())
        return "\n".join(results)

# 用法
facade = Facade()
facade.operation()

11. 享元(Flyweight):

* 重用共享的對象,以支持大量細粒度的對象。

import json
import random

class Flyweight:
    def __init__(self, shared_state):
        self.shared_state = shared_state  

    def operation(self, unique_state):
        s = json.dumps(self.shared_state)  
        u = json.dumps(unique_state)
        print(f"Flyweight: Displaying shared {s} and unique {u} state.", end="")

class FlyweightFactory:
    _flyweights = {}

    def __init__(self, initial_flyweights):
        for state in initial_flyweights:
            self._flyweights[self.get_key(state)] = Flyweight(state)

    def get_key(self, state):
        return "_".join(sorted(state))

    def get_flyweight(self, shared_state):
        key = self.get_key(shared_state)

        if not self._flyweights.get(key):
            print("FlyweightFactory: Can't find a flyweight, creating new one.")
            self._flyweights[key] = Flyweight(shared_state)
        else:
            print("FlyweightFactory: Reusing existing flyweight.")

        return self._flyweights[key]

    def list_flyweights(self):
        count = len(self._flyweights)
        print(f"FlyweightFactory: I have {count} flyweights:")
        print("\n".join(map(str, self._flyweights.keys())), end="")

# 用法
factory = FlyweightFactory([
    ["Chevrolet", "Camaro2018", "pink"], 
    ["Mercedes Benz", "C300", "black"],
    ["Mercedes Benz", "C500", "red"]  
])

factory.list_flyweights()
 
fl1 = factory.get_flyweight(["pink"])
fl2 = factory.get_flyweight(["red","4-doors"]) 
fl3 = factory.get_flyweight(["black"])

fl1.operation(["10"])
fl2.operation(["V8"])
fl3.operation([])

12. 代理(Proxy):

* 使用代理對象來代替其他對象控制訪問。

from abc import ABC, abstractmethod

class Subject(ABC):
    """定義RealSubject與Proxy的通用接口"""

    @abstractmethod
    def request(self):
        pass

class RealSubject(Subject):
    """定義Proxy所代表的實體類"""

    def request(self):
        print("RealSubject: Handling request.")

class Proxy(Subject):
    """保存一個引用使得Proxy可以訪問實體對象"""

    def __init__(self, real_subject):
        self._real_subject = real_subject

    def request(self):
        """通過保護代理添加一個控制層"""
        print("Proxy: Checking access prior to firing a real request.")
        self._real_subject.request()

# 用法  
real = RealSubject()
proxy = Proxy(real)
proxy.request()

13. 鏈式責任(Chain of Responsibility):

* 使多個對象都有可能處理請求,從而避免請求的發送者和接收者之間的耦合關系。

from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any

class Handler(ABC):
    """定義一個處理請求的介面"""

    @abstractmethod
    def set_next(self, handler: Handler) -> Handler:
        pass

    @abstractmethod
    def handle(self, request) -> None:
        pass

class BaseHandler(Handler):
    """ 鏈中最後一個處理者,通常做默認處理 """

    def set_next(self, handler: Handler) -> Handler:
        pass

    def handle(self, request):
        print("End of chain, no handler for this request!")

class AbstractHandler(Handler):
    """鏈中的處理者,通過一個字段組合該鏈"""

    _next_handler: Handler = None

    def set_next(self, handler: Handler) -> Handler:
        self._next_handler = handler
        return handler

    @abstractmethod
    def handle(self, request: Any) -> None:
        if self._next_handler:
            return self._next_handler.handle(request)

        return None

class ConcreteHandler1(AbstractHandler):
    """定義具體處理者"""

    def handle(self, request: Any) -> str:
        if request == "one":
            print("ConcreteHandler1 handled request")
            return

        super().handle(request)

class ConcreteHandler2(AbstractHandler):
    """定義具體處理者"""

    def handle(self, request: Any) -> str:
        if request == "two":
            print("ConcreteHandler2 handled request")
            return

        super().handle(request)
        
# 用法
def client_code(handler: Handler) -> None:
    for request in ["one", "two", "three"]:
        print(f"\nClient: Who wants to handle {request}?")
        handler.handle(request)

base = BaseHandler()
h1 = ConcreteHandler1()
h2 = ConcreteHandler2()

h1.set_next(h2).set_next(base)  
client_code(h1)

14. 命令(Command):

* 封裝請求為對象,從而可以使用不同的請求把客戶和接收者解耦。

from __future__ import annotations
from abc import ABC, abstractmethod

class Command(ABC):
    """定義命令接口"""
    
    @abstractmethod
    def execute(self) -> None:
        pass

class SimpleCommand(Command):
    """定義一些命令"""

    def __init__(self, payload: str) -> None:
        self._payload = payload

    def execute(self) -> None:
        print(f"SimpleCommand: See, I can do simple things like printing ({self._payload})")


class ComplexCommand(Command):
    """示範可以封裝任何數量的命令"""

    def __init__(self, receiver: Receiver, a: str, b: str) -> None:
        """複雜命令可以定義一系列命令"""
        self._receiver = receiver
        self._a = a
        self._b = b

    def execute(self) -> None:
        """命令的執行方法"""
        
        print("ComplexCommand: Complex stuff should be done by a receiver object", end="")
        self._receiver.do_something(self._a)
        self._receiver.do_something_else(self._b)

class Receiver:
    """示範命令協作對象"""

    def do_something(self, a: str) -> None:
        print(f"\nReceiver: Working on ({a}.)", end="")

    def do_something_else(self, b: str) -> None:
        print(f"\nReceiver: Also working on ({b}.)", end="")
        
class Invoker:
    """要求提供命令接口的調用方"""

    _on_start = None
    _on_finish = None

    def set_on_start(self, command: Command):
        self._on_start = command

    def set_on_finish(self, command: Command):
        self._on_finish = command

    def do_something_important(self) -> None:

        print("Invoker: Does anybody want something done before I begin?")
        if isinstance(self._on_start, Command):
            self._on_start.execute()

        print("Invoker: ...doing something really important...")

        print("Invoker: Does anybody want something done after I finish?")
        if isinstance(self._on_finish, Command):
            self._on_finish.execute()

# 用法
invoker = Invoker()
invoker.set_on_start(SimpleCommand("Say Hi!"))
receiver = Receiver()
invoker.set_on_finish(ComplexCommand(
    receiver, "Send email", "Save report"))

invoker.do_something_important()

15. 解譯器(Interpreter):

* 給每個語法規則提供一個對應的解譯類別。

from abc import ABC, abstractmethod
from typing import List


class Expression(ABC):
    """定義剖析器規則的基類"""
    
    @abstractmethod
    def interpret(self):
        pass

class TerminalExpression(Expression):
    """終端符號剖析規則"""
    
    def __init__(self, data) -> None:
        self.data = data
        
    def interpret(self):
        return self.data

class NonterminalExpression(Expression):    
    """非終端符號剖析規則"""
    
    def __init__(self, expression: List[Expression]) -> None:
        self.expression = expression
        
    def interpret(self):        
        result = []       
        for exp in self.expression:
            value = exp.interpret()            
            result.append(value)
            
        return ' '.join(result)
        
# 用法 
ast = [
    TerminalExpression("Hello"),
    TerminalExpression("World")    
]

nonterminal = NonterminalExpression(ast)
nonterminal.interpret()

16. 迭代器(Iterator):

* 提供一種順序訪問一系列對象的方法,而不需要暴露這些對象的內部細節。

class AlphabeticalOrderIterator:
    """具體迭代器"""

    _position: int = None

    """迭代器應該追蹤它們所迭代的當前項目"""
    _reverse: bool = False

    def __init__(self, collection, reverse: bool = False) -> None:
        self._collection = collection
        self._reverse = reverse
        self._position = -1 if reverse else 0

    def __next__(self):
        """移動到下一個元素"""
        try:
            value = self._collection[self._position]
            self._position += -1 if self._reverse else 1
        except IndexError:
            raise StopIteration()

        return value
    
    def __iter__(self):
        return self

# 用法
collection = ["a", "b", "c", "d"]
iterator = AlphabeticalOrderIterator(collection)
for item in iterator:
    print(item)
    
# 反向迭代    
reverse_iterator = AlphabeticalOrderIterator(collection, reverse=True)
for item in reverse_iterator:
    print(item)

17. 中介者(Mediator):

* 用中介對象去封裝一系列摯交組的互動,降低他們的依賴性。

from __future__ import annotations
from abc import ABC


class Mediator(ABC):
    """定義一個接口用於組件與中介者的通信"""

    def notify(self, sender: object, event: str) -> None:
        pass

class ConcreteMediator(Mediator):
    def __init__(self, component1, component2):
        self.component1 = component1
        self.component1.mediator = self
        self.component2 = component2
        self.component2.mediator = self

    def notify(self, sender, event):
        if event == "A":
            print("中介者 reacts on A and triggers folowing operations:")
            self.component2.do_c()
        elif event == "D":
            print("中介者 reacts on D and triggers following operations:")
            self.component1.do_b()
            self.component2.do_c()

class BaseComponent:
    """各組件共同點,知曉中介者"""

    def __init__(self, mediator: Mediator = None) -> None:
        self._mediator = mediator

    @property
    def mediator(self) -> Mediator:
        return self._mediator

    @mediator.setter
    def mediator(self, mediator: Mediator) -> None:
        self._mediator = mediator

class Component1(BaseComponent):
    """具體組件 1"""

    def do_a(self):
        print("Component 1 does A.")
        self.mediator.notify(self, "A")

    def do_b(self):
        print("Component 1 does B.")
        self.mediator.notify(self, "B")

class Component2(BaseComponent):
    """具體組件 2"""

    def do_c(self):
        print("Component 2 does C.")
        self.mediator.notify(self, "C")

    def do_d(self):
        print("Component 2 does D.")
        self.mediator.notify(self, "D")

# 用法
c1 = Component1()
c2 = Component2()
mediator = ConcreteMediator(c1, c2)

print("Client triggets operation A.")
c1.do_a()

print()

print("Client triggers operation D.")
c2.do_d()

18. 備忘模式(Memento):

* 在不破壞封裝性的前提下擷取一個對象的內部狀態以便以後恢復。

import datetime

class Memento:
    def __init__(self, state):
        self._state = state
        self._date = datetime.date.today()

    def get_state(self):
        return self._state

    def get_date(self):
        return self._date

class Originator:

    def __init__(self, state):
        self._state = state        

    def create_memento(self):
        print(f"Originator: Saving {self._state}")
        return Memento(self._state)

    def get_state(self):
        return self._state

    def set_memento(self, memento):
        self._state = memento.get_state()
        print(f"Originator: Previous state {self._state} restored")


originator = Originator("State 1")
memento = originator.create_memento()

originator._state = "State 2"
print(f"Originator: Current State = {originator._state}")

originator.set_memento(memento)
print(f"Originator: Current State = {originator._state}")

19. 觀察者(Observer):

* 定義對象和觀察者之間的依賴關系,使得當對象改變狀態時,其相關依賴都會得到通知並更新。

from __future__ import annotations
from abc import ABC, abstractmethod
from random import randrange
from typing import List

class Subject(ABC):
    """定義主題接口"""

    @abstractmethod
    def attach(self, observer: Observer) -> None:
        """附加觀察者"""
        pass

    @abstractmethod
    def detach(self, observer: Observer) -> None:
        """分離觀察者"""
        pass

    @abstractmethod
    def notify(self) -> None:
        """發送更新給連線的觀察者"""
        pass
    
    
class ConcreteSubject(Subject):
    """定義主題"""

    _state: int = None
    """一些重要狀態,觀察者留意"""

    _observers: List[Observer] = []
    """所有當前註冊的觀察者列表"""

    def attach(self, observer: Observer) -> None:
        print("Subject: Attached an observer.")
        self._observers.append(observer)

    def detach(self, observer: Observer) -> None:
        self._observers.remove(observer)

    """根據主體內部狀態發送更新給觀察者"""

    def notify(self) -> None:
        print("Subject: Notifying observers...")
        for observer in self._observers:
            observer.update(self)

    def some_business_logic(self) -> None:
        """通常會改變的業務邏輯"""

        print("\nSubject: I'm doing something important.")
        self._state = randrange(0, 10)

        print(f"Subject: My state has just changed to: {self._state}")
        self.notify()

class Observer(ABC):
    """定義觀察者接口"""

    @abstractmethod
    def update(self, subject: Subject) -> None:
        """接收更新時調用"""
        pass

class ConcreteObserverA(Observer):
    def update(self, subject: Subject) -> None:
        if subject._state < 3:
            print("ConcreteObserverA: Reacted to the event")

class ConcreteObserverB(Observer):
    def update(self, subject: Subject) -> None:
        if subject._state == 0 or subject._state >= 2:
            print("ConcreteObserverB: Reacted to the event")

# 用法            
subject = ConcreteSubject()

observer_a = ConcreteObserverA()
subject.attach(observer_a)

observer_b = ConcreteObserverB()
subject.attach(observer_b)

subject.some_business_logic()
subject.some_business_logic()

subject.detach(observer_a)

subject.some_business_logic()

20. 狀態(State):

* 允許對象在內部狀態改變時改變行為,對象看起來好像改變了類別一樣。

from abc import ABC, abstractmethod


class Context:
    """定義通過轉換狀態 Context 類的接口。保存一個具體狀態的實例"""

    _state = None
    """狀態實例"""

    def __init__(self, state) -> None:
        self.transition_to(state)

    def transition_to(self, state):
        """切換狀態"""
        
        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    """調用者會將請求委派給當前狀態"""

    def request1(self):
        self._state.handle1()

    def request2(self):
        self._state.handle2()

class State(ABC):
    """定義一個接口用於封裝與 Context 的一種特定狀態相關的行為"""

    @property
    def context(self) -> Context:
        return self._context

    @context.setter
    def context(self, context: Context) -> None:
        self._context = context

    @abstractmethod
    def handle1(self):
        pass

    @abstractmethod
    def handle2(self):
        pass

"""具體狀態"""

class ConcreteStateA(State):
    def handle1(self):
        print("ConcreteStateA handles request1.")
    
    def handle2(self):
        print("ConcreteStateA handles request2.")
        self.context.transition_to(ConcreteStateB())

class ConcreteStateB(State):
    def handle1(self):
        print("ConcreteStateB handles request1.")

    def handle2(self):
        print("ConcreteStateB handles request2.")
        self.context.transition_to(ConcreteStateA())

# 用法
context = Context(ConcreteStateA())
context.request1()
context.request2()

21. 策略(Strategy):

* 定義一系列演算法,分別封裝起來,使得它們可以互換。

from abc import ABC, abstractmethod

class Strategy(ABC):
    """定義策略類的接口"""
    
    @abstractmethod
    def execute(self, data):
        pass
        
"""實現各類策略"""
  
class ConcreteStrategyA(Strategy):
    def execute(self, data):
        print("Strategy A: ", data)
        
class ConcreteStrategyB(Strategy):
    def execute(self, data): 
        print("Strategy B: ", data)
        
class Context():     
    """使控制該策略的父級"""

    def __init__(self, strategy: Strategy) -> None:
        """屬於 Context 的某策略"""        
        self._strategy = strategy

    @property
    def strategy(self) -> Strategy:
        """策略切換"""
        
        return self._strategy

    @strategy.setter
    def strategy(self, strategy: Strategy) -> None:
        """改變策略通過 Context 聲明"""
        
        self._strategy = strategy
        
    def do_some_business_logic(self):
        """Context 提供資訊給 strategy 執行演算法"""
        
        print("Context: Sorting data using the strategy (not sure how it'll do it)")
        result = self._strategy.execute(["a", "b", "c", "d", "e"])
        print(result)

# 用法
context = Context(ConcreteStrategyA()) 
print("Client: Strategy is set to normal sorting.")
context.do_some_business_logic()

print()

context.strategy = ConcreteStrategyB()
print("Client: Strategy is set to reverse sorting.")
context.do_some_business_logic()

22. 範本模式(Template Pattern):

* 將算法的一些步驟推遲到子類別中實現,子類別無需改變算法的結構即可重定義該算法的某些步驟。

from abc import ABC, abstractmethod

class AbstractClass(ABC):
    """定義模板方法的框架"""
    
    def template_method(self) -> None:
        """模板方法定義了一個演算法的框架"""
        
        self.base_operation1()
        self.required_operations1() 
        self.base_operation2()
        self.hook1()
        self.required_operations2()
        self.base_operation3()
        self.hook2()

    """對子類別來說是選擇性的模板方法"""
    
    def base_operation1(self) -> None:
        print("AbstractClass says: I am doing the bulk of the work")

    def base_operation2(self) -> None:
        print("AbstractClass says: But I let subclasses override some operations")
        
    def base_operation3(self) -> None:
        print("AbstractClass says: But I am doing the bulk of the work anyway")

    """隨主類別實現"""
        
    @abstractmethod
    def required_operations1(self) -> None:
        pass

    @abstractmethod
    def required_operations2(self) -> None:
        pass

    """這些行為有默認實現"""
       
    def hook1(self) -> None:
        pass

    def hook2(self) -> None:
        pass


class ConcreteClass1(AbstractClass):
    """定義具體子類"""
    
    def required_operations1(self) -> None:
        print("ConcreteClass1 says: Implemented Operation1")

    def required_operations2(self) -> None:
        print("ConcreteClass1 says: Implemented Operation2")

class ConcreteClass2(AbstractClass):
    """定義另一個子類"""
    
    def required_operations1(self) -> None:
        print("ConcreteClass2 says: Implemented Operation1")

    def required_operations2(self) -> None:
        print("ConcreteClass2 says: Implemented Operation2")

def client_code(abstract_class: AbstractClass) -> None:
    """模板方法在客戶端代碼工作"""

    abstract_class.template_method()

# 用法
print("Same client code can work with different subclasses:")
client_code(ConcreteClass1())
client_code(ConcreteClass2())

23. 訪問者(Visitor):

* 表示作用在某物件結構上的操作,它使你可以在不改變這些類別的前提下定義作用在這些元素的新操作。

from __future__ import annotations
from abc import ABC, abstractmethod


class Component(ABC):
    """定義一個訪問者可以在的所有元素的接口"""

    @abstractmethod
    def accept(self, visitor: Visitor) -> None:
        pass

class ConcreteComponentA(Component):
    """各部分會實現導入訪問者的 accept() 方法"""

    def accept(self, visitor: Visitor) -> None:
        """訪問者在必要時可能獲取被訪問元素"""
        visitor.visit_concrete_component_a(self)

    def exclusive_method_of_concrete_component_a(self) -> str:
        """具體元素也可以定義自己的業務邏輯"""
        return "A"

class ConcreteComponentB(Component):
    """同理,其他元素實現 accept 方法"""

    def accept(self, visitor: Visitor):
        visitor.visit_concrete_component_b(self)

    def special_method_of_concrete_component_b(self) -> str:
        return "B"

class Visitor(ABC):
    """定義訪問者將必須實現的接口"""

    @abstractmethod
    def visit_concrete_component_a(self, element: ConcreteComponentA) -> None:
        pass

    @abstractmethod
    def visit_concrete_component_b(self, element: ConcreteComponentB) -> None:
        pass

"""具體訪問者將在每個新具體元素類時實現一些業務邏輯"""

class ConcreteVisitor1(Visitor):
    def visit_concrete_component_a(self, element) -> None:
        print(f"{element.exclusive_method_of_concrete_component_a()} + ConcreteVisitor1")

    def visit_concrete_component_b(self, element) -> None:
        print(f"{element.special_method_of_concrete_component_b()} + ConcreteVisitor1")

class ConcreteVisitor2(Visitor):
    def visit_concrete_component_a(self, element) -> None:
        print(f"{element.exclusive_method_of_concrete_component_a()} + ConcreteVisitor2")

    def visit_concrete_component_b(self, element) -> None:
        print(f"{element.special_method_of_concrete_component_b()} + ConcreteVisitor2")

def client_code(components: list, visitor: Visitor) -> None:
    """客戶端代碼透過 accept 方法對各組件運行訪問者"""
    
    for component in components:
        component.accept(visitor)

# 用法
components = [ConcreteComponentA(), ConcreteComponentB()]

print("The client code works with all visitors via the base Visitor interface:")
visitor1 = ConcreteVisitor1()
client_code(components, visitor1)
    
print()

visitor2 = ConcreteVisitor2()
client_code(components, visitor2)
1個讚