python设计模式-结构型模式

适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

  • 适用场景:

    • 系统需要使用现有的类,而此类的接口不符合系统的需要。
    • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
    • 通过接口转换,将一个类插入另一个类系中。
  • 优点:

    • 可以让任何两个没有关联的类一起运行。
    • 提高了类的复用。
    • 增加了类的透明度。
    • 灵活性好。
  • 缺点:

    • 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
from abc import abstractmethod, ABCMeta


class OldLogger:
    """
    抽象化角色
    """

    def debug(self, msg):
        print(f"旧的日志器:{msg}")


class NewLogger:
    def new_debug(self, msg):
        print(f"新的日志器:{msg}")


class AdapterLogger(OldLogger):
    def __init__(self, logger: NewLogger):
        self.logger = logger

    def debug(self, msg):
        self.logger.new_debug(msg)


def main(log: OldLogger):
    log.debug("调试中")


if __name__ == "__main__":
    logger = AdapterLogger(NewLogger())
    main(logger)

桥接模式

桥接模式就是把抽象部分与实现部分抽离,使其可以匹配多种组合
说白了就是将俩种不同维度的事物进行任意组合使用,防止产生笛卡尔积

  • 为什么要使用桥接模式

    商城系统中常见的商品分类,以电脑分类为例,我们可以使用多层继承结构
    python设计模式-结构型模式_第1张图片

    假设加上一个品牌,荣耀,那么我们就需要再创建一个品牌抽象,实现3个分类。一个两个还好,如果添加100个种类呢?就会发生类爆炸(类贼多),后期维护复杂,违反单一职责原则。

  • 桥接模式结构

    桥,顾名思义就是用来将河的两岸联系起来的。而此处的桥是用来将两个独立的结构联系起来,而这两个被联系起来的结构可以独立的变化。而实现桥接模式的具体操作就是将抽象化部分与实现化部分分开,取消二者的继承关系,改用组合关系,并用连接

    • 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用()作为实例属性。
    • 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
    • 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
    • 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
  • 代码示例

from abc import abstractmethod, ABCMeta


class AbstractPen(metaclass=ABCMeta):
    """
    抽象化角色
    """

    def __init__(self, shape):
        self.shape = shape  # 对实现化对象的引用
    @abstractmethod
    def draw(self):
        raise NotImplementedError


class GreenPen(AbstractPen):
    """
    扩展抽象化角色:绿色笔
    """

    def draw(self):
        print("我用绿色画笔,", end='')
        self.shape.draw()


class RedPen(AbstractPen):
    """
    扩展抽象化角色:红色笔
    """

    def draw(self):
        print("我用红色画笔,", end='')
        self.shape.draw()


class AbstractShape(metaclass=ABCMeta):
    """
    实现化角色
    """

    @abstractmethod
    def draw(self):
        raise NotImplementedError


class Circle(AbstractShape):
    """
    具体实现化角色:圆形
    """

    def draw(self):
        print("圆形")


class Rectangle(AbstractShape):
    """
    具体实现化角色:矩形
    """

    def draw(self):
        print("矩形")


if __name__ == "__main__":
    RedPen(Rectangle()).draw()
  • 优点:

    • 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
    • 在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
    • 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。
  • 缺点:

    • 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
    • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。

过滤器模式

  • 示例代码
class Customer:
    def __init__(self, name, gender, age, address):
        self.name = name
        self.gender = gender
        self.age = age
        self.address = address


class Filter:
    def execute(self, customers):
        pass


class GenderFilter(Filter):
    def __init__(self, gender):
        self.gender = gender

    def execute(self, customers):
        result = []
        for customer in customers:
            if customer.gender == self.gender:
                result.append(customer)
        return result


class AgeFilter(Filter):
    def __init__(self, min_age, max_age):
        self.min_age = min_age
        self.max_age = max_age

    def execute(self, customers):
        result = []
        for customer in customers:
            if self.min_age <= customer.age <= self.max_age:
                result.append(customer)
        return result


class AddressFilter(Filter):
    def __init__(self, address):
        self.address = address

    def execute(self, customers):
        result = []
        for customer in customers:
            if customer.address == self.address:
                result.append(customer)
        return result


class CustomerDataAnalysis:
    def __init__(self, customers):
        self.customers = customers

    def apply_filter(self, filter_obj):
        filtered_customers = filter_obj.execute(self.customers)
        return filtered_customers


if __name__ == '__main__':
    customers = [
        Customer("Tom", "Male", 27, "Beijing"),
        Customer("Jerry", "Male", 32, "Shanghai"),
        Customer("Lucy", "Female", 24, "Guangzhou"),
        Customer("Lily", "Female", 38, "Shenzhen"),
        Customer("Jack", "Male", 29, "Beijing"),
    ]
    analysis = CustomerDataAnalysis(customers)
    result = analysis.apply_filter(GenderFilter("Male"))
    print("Male Customers:")
    for customer in result:
        print(customer.name)
    result = analysis.apply_filter(AgeFilter(25, 35))
    print("Customers between 25 and 35 years old:")
    for customer in result:
        print(customer.name)
    result = analysis.apply_filter(AddressFilter("Shanghai"))
    print("Customers from Shanghai:")
    for customer in result:
        print(customer.name)

组合模式

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

  • 使用场景
    • 对象的部分-整体层次结构(树形结构,文件件,菜单等)。
    • 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
  • 优点
    • 高层模块调用简单。
    • 节点自由增加。
  • 缺点
    • 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
  • 代码示例
from abc import ABC, abstractmethod


class Component(ABC):
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def operation(self, depth):
        pass

    @abstractmethod
    def add(self, c):
        pass

    @abstractmethod
    def remove(self, c):
        pass

    @abstractmethod
    def get_child(self, index):
        pass


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

    def operation(self, depth):
        strtemp = ''
        for i in range(depth):
            strtemp += strtemp+'-'
        print(strtemp+self.name)
        for comp in self.children:
            comp.operation(depth+2)

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

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

    def get_child(self, index):
        return self.children[index]


class Leaf(Component):
    def operation(self, depth):
        strtemp = ''
        for i in range(depth):
            strtemp += strtemp+'-'
        print(strtemp+self.name)

    def add(self, c):
        print('不能添加下级节点!')

    def remove(self, c):
        print('不能删除下级节点!')

    def get_child(self, index):
        print('没有下级节点!')


class Client:
    @staticmethod
    def main():
        # 生成树根
        root = Composite("root")
        # 根上长出2个叶子
        root.add(Leaf('leaf A'))
        root.add(Leaf('leaf B'))
        # 根上长出树枝Composite X
        comp = Composite("Composite X")
        comp.add(Leaf('leaf XA'))
        comp.add(Leaf('leaf XB'))
        root.add(comp)
        # 根上长出树枝Composite X
        comp2 = Composite("Composite XY")
        # Composite X长出2个叶子
        comp2.add(Leaf('leaf XYA'))
        comp2.add(Leaf('leaf XYB'))
        root.add(comp2)
        # 根上又长出2个叶子,C和D,D没长好,掉了
        root.add(Leaf('Leaf C'))
        leaf = Leaf("Leaf D")
        root.add(leaf)
        root.remove(leaf)
        # 展示组织
        root.operation(1)


if __name__ == '__main__':
    Client.main()

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象扩展新的功能,同时不改变其结构。主要解决直接继承下因功能的不断横向扩展导致子类膨胀的问题,无需考虑子类的维护。

  • 使用场景
    • 扩展一个类的功能。
    • 动态增加功能,动态撤销。
  • 装饰器模式的4种角色:
    • 抽象构件角色(Component):具体构件类和抽象装饰者类的共同父类。
    • 具体构件角色(ConcreteComponent):抽象构件的子类,装饰者类可以给它增加额外的职责。
    • 装饰角色(Decorator):抽象构件的子类,具体装饰类的父类,用于给具体构件增加职责,但在子类中实现。
    • 具体装饰角色(ConcreteDecorator):每一个具体装饰类都定义了一些新的行为,负责向构件添加新的职责。
  • 优点
    • 不改动原有代码,动态增加功能。
    • 对象间不会相互依赖、松耦合。
    • 符合开闭原则,扩展性好,便于维护。
  • 缺点
    • 装饰器环节过多的话,导致装饰器类膨胀。
    • 装饰器层层嵌套比较复杂,可能导致排查问题流程繁琐
  • 代码示例
from abc import abstractmethod, ABCMeta


class IMilktea(metaclass=ABCMeta):
    """
    抽象构件(Component)角色:奶茶
    """

    @abstractmethod
    def add_dosing(self): ...


class PearlMilktea(IMilktea):
    """
    具体构件(ConcreteComponent)角色:珍珠奶茶
    """

    def add_dosing(self):
        print("开始制作:珍珠奶茶")


class LemonMilktea(IMilktea):
    """
    具体构件(ConcreteComponent)角色:柠檬水奶茶
    """

    def add_dosing(self):
        print("开始制作:柠檬水")


class Dosing(IMilktea):
    """
    装饰(Decorator)角色:配料
    """

    def __init__(self, imilk_tea: IMilktea):
        self.imilk_tea = imilk_tea

    def add_dosing(self):
        self.imilk_tea.add_dosing()


class Pearl(Dosing):
    """
    具体装饰(ConcreteDecorator)角色
    """

    def add_dosing(self):
        super(Pearl, self).add_dosing()
        print("制作中:加珍珠")


class Mango(Dosing):
    """
    具体装饰(ConcreteDecorator)角色
    """

    def add_dosing(self):
        super(Mango, self).add_dosing()
        print("制作中:加芒果")


if __name__ == "__main__":
    tea = PearlMilktea()
    tea = Pearl(tea)
    tea = Mango(tea)
    tea.add_dosing()

外观模式

Python 外观模式是一种常见的设计模式,它提供了一种简单的方式来组合多个复杂的子系统,使其对外表现为一个简单的接口。

  • 外观模式结构:
    • 外观类(Facade Class):提供一个简单的接口,将子系统中的多个复杂类组合起来,对客户端隐藏子系统的实现细节。
    • 子系统类(Sub System Classes):包含多个复杂的子系统,实现了外观接口所声明的功能。
    • 客户端类(Client Class):通过外观接口访问子系统,与外观类进行交互。
  • 代码示例
class SubSystemA:
    def method_a(self):
        print("SubSystemA method_a() called.")
 class SubSystemB:
    def method_b(self):
        print("SubSystemB method_b() called.")
 class SubSystemC:
    def method_c(self):
        print("SubSystemC method_c() called.")
 class Facade:
    def __init__(self):
        self._subsystem_a = SubSystemA()
        self._subsystem_b = SubSystemB()
        self._subsystem_c = SubSystemC()
     def operation(self):
        self._subsystem_a.method_a()
        self._subsystem_b.method_b()
        self._subsystem_c.method_c()
 class Client:
    def __init__(self):
        self._facade = Facade()
     def run(self):
        self._facade.operation()
client = Client()
client.run()

享元模式

Python 享元模式是一种优化性的设计模式,它通过共享对象来减少系统中的对象数量,从而提高了系统的性能。该模式的核心思想是将大量的细粒度对象共享,使得系统中实际存在的对象数量极少。
享元模式有两个主要角色:

  1. 享元工厂类(Flyweight Factory Class):负责创建和管理享元对象,以确保对象的共享。
  2. 享元对象类(Flyweight Object Class):包含内部状态和外部状态两部分,内部状态存储于对象内部,外部状态则由客户端通过参数传入。
  • 代码示例
class Flyweight:
    def __init__(self, shared_state):
        self._shared_state = shared_state

    def operation(self, unique_state):
        print(f"Flyweight: Displaying shared ({self._shared_state}) and unique ({unique_state}) state.")


class FlyweightFactory:
    def __init__(self):
        self._flyweights = {}

    def get_flyweight(self, shared_state):
        if shared_state not in self._flyweights:
            self._flyweights[shared_state] = Flyweight(shared_state)
        return self._flyweights[shared_state]

    def list_flyweights(self):
        print(f"FlyweightFactory: I have {len(self._flyweights)} flyweights:")
        for key in self._flyweights.keys():
            print(key)


if __name__ == "__main__":
    factory = FlyweightFactory()

    flyweight1 = factory.get_flyweight("state_1")
    flyweight1.operation("unique_1")

    flyweight2 = factory.get_flyweight("state_2")
    flyweight2.operation("unique_2")

    flyweight3 = factory.get_flyweight("state_1")
    flyweight3.operation("unique_3")

    factory.list_flyweights()

代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。在代理模式中,我们创建具有现有对象的代理对象,以控制对原有对象的访问。

  • 使用场景,按职责来划分,通常有以下使用场景:

    • 远程代理。
    • 虚拟代理。
    • Copy-on-Write 代理。
    • 保护(Protect or Access)代理。
    • Cache代理。
    • 防火墙(Firewall)代理。
    • 同步化(Synchronization)代理。
    • 智能引用(Smart Reference)代理。
  • 优点

    1、职责清晰。 2、高扩展性。 3、智能化。

  • 缺点

    • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
    • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 代码示例

import abc


class BaseStation(abc.ABC):
    @abc.abstractmethod
    def create_tickets(self, start, end): ...


class TrainStation(BaseStation):
    """
    火车站
    """

    def create_tickets(self, start, end):
        print(f"打印从{start}-{end}车票一张")


class ProxyPoint(BaseStation):
    """
    代售点
    """

    def __init__(self):
        self.__train_station = TrainStation()

    def create_tickets(self, start, end):
        print('通过代售点')
        self.__train_station.create_tickets(start, end)


if __name__ == '__main__':
    proxy = ProxyPoint()
    proxy.create_tickets('nanjing', 'beijing')

你可能感兴趣的:(设计模式,设计模式,python,java)