2020-12-15 《大话设计模式》之 设计原则 与 装饰模式

几个设计原则

1. 单一职责原则

2. 开放-封闭原则

Open for extension, closed for modification.
对扩展开放,对修改关闭(接受现实,拥抱未来);
面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码;
建立抽象,分离,令代码可维护、可扩展、可复用、灵活性好;
但是尽量在开发初期就知道可能发生的变化,查明可能发生的变化等待的时间越长,要创建正确的抽象就越困难;
拒绝不成熟的抽象。

3. 依赖倒转原则

强内聚 松耦合

高层模块不应该依赖低层模块,两个都应该依赖抽象
抽象不应该依赖细节,细节应该依赖抽象

程序中的所有依赖关系都终止于抽象类或者接口

里氏代换原则(LSP):子类型必须能够替换掉他们的父类型


装饰模式

1. 基础类:

  • 基础接口 定义一系列操作
  • 基础装饰类 初始化时传入基础接口类并储存 操作时对储存的基础接口类进行操作达到串联的效果(类似 super().interface_method())

2. 实例化:

  • 自定义基础接口的不同实现1
  • 自定义基础接口的不同实现2
  • ...
  • 自定义装饰类1 对基础接口的部分操作重写 重写时必须对基础装饰类在初始化储存的基础接口类的同名函数进行调用以达到串联的效果
    并且可以在调用前后执行任意任务装饰的关键步骤在这里
  • 自定义装饰类2 同上
  • ...

3. 使用:

未使用装饰的基本用法:对基础接口的实现,实例化,然后执行一系列操作
使用装时候:将实例连续包裹传入自定义装饰类(注意装饰的顺序会影响执行结果),再执行一系列操作

4. 示例一(所有interface的methods均为需要被实现的实例方法):

# decorator_demo_for_instance_methods.py
from abc import ABC, abstractmethod


class Notice(ABC):
    """Base Component
    must implement get_content(extra info) and
    notify(routine method exposed to external)
    """
    @abstractmethod
    def get_content(self) -> str:
        pass
    @abstractmethod
    def notify(self):
        pass
class SimpleNotice(Notice):
    """Component Implementation"""
    def get_content(self) -> str:
        return "Notice Content"
    def notify(self):
        print(f"Console Notice: {self.get_content()}")


class Decorator(Notice):
    """Base Decorator
    1. Pass and save the base component while initializing
    2. Re-write method get_content(for extra info) 
    and most importantly, the routine method notify,
    by calling the original method

    Notice:
        The decorator was inherited from Notice, so every abstract
        method, including property method(if any) should be re-write
    """
    _notice: Notice = None
    def __init__(self, notice: Notice) -> None:
        self._notice = notice
    @property
    def notice(self) -> str:
        return self._notice
    def get_content(self) -> str:
        """Calling the original method"""
        return self.notice.get_content()
    def notify(self):
        """Calling the original method"""
        self.notice.notify()

class EmailDecorator(Decorator):
    """Decorator Variant 1
    re-write the routine method, which is the notify method
    do something before/after the routing method
    """
    def notify(self):
        print(f"Email Notified: {self.get_content()}")
        self.notice.notify()
        print(f"Email Decorator After")

class WeChatDecorator(Decorator):
    """Decorator Variant 2"""
    def notify(self):
        print(f"WeChat Notified: {self.get_content()}")
        self.notice.notify()
        print(f"WeChat Decorator After")

def client_code(notice: Notice) -> None:
    # Call the routine method, the notice variable passed
    # might be a subclass directly inherited from Notice
    # or the wrapper wrapped by the decorator
    notice.notify()


if __name__ == "__main__":
    # This way the client code can support both simple notices...
    simple = SimpleNotice()
    print("Client: Calling a routine for a simple notice:")
    client_code(simple)
    print("")

    # ...as well as decorated ones.
    #
    # Note how decorators can wrap not only simple notices but the other
    # decorators as well.
    # BTW, the order mattters
    decorator1 = EmailDecorator(simple)
    decorator2 = WeChatDecorator(decorator1)
    print("Client: Decorated notice:")
    client_code(decorator2)

Outputs:

$ python decorator_demo_for_instance_methods.py
Client: Calling a routine for a simple notice:
Console Notice: Notice Content

Client: Decorated notice:
WeChat Notified: Notice Content
Email Notified: Notice Content
Console Notice: Notice Content
Email Decorator After
WeChat Decorator After

5. 示例二:需要实现property abstractmethod(这里没有写出完整的代码,仅点出要点,详细的实现流程参照4)

class MyProperty:
    def __set_name__(self, owner, name):
        self.private_name = "_" + name
    def __get__(self, obj, objtype=None):
        return getattr(obj, self.private_name)
    def __set__(self, obj, value):
        setattr(obj, self.private_name, value)
class Component:
    @property
    @abstractmethod
    def p(self):
        pass
class ConcreteComponent(Component):
    p = MyProperty()
class Decorator(Component):
    p = MyProperty() # Decorator must rewrite the descriptor

Keywords

design principle, decorator, single responsibility principle

参考

  1. 《大话设计模式》, 2007年7月,作者程杰
  2. Design Pattern - Refactoring

你可能感兴趣的:(2020-12-15 《大话设计模式》之 设计原则 与 装饰模式)