HOME/Articles/

结构型模式

Article Outline

适配器模式

title

  • 意图:将一个类的接口转换成客户希望的另一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

  • 适用性:

    1. 想使用一个已经存在的类,而它的接口不符合你的需求

    2. 想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作

    3. 想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口

class Human:
    def __init__(self,name):
        self.name = name

    def __str__(self):
        return "The human's name is {}\n".format(self.name)

    def speak(self):
        return "Hello!"

class Dog:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "The dog's name is {}\n".format(self.name)

    def bark(self):
        return "Woof!"

class Adapter:
    def __init__(self, obj, adapted_methods):
        self.obj = obj
        self.__dict__.update(adapted_methods)

    def __str__(self):
        return  str(self.obj)

if __name__ == '__main__':
    objects = []
    objects.append(Human('human'))
    dog = Dog("dog")
    objects.append(Adapter(dog, dict(speak = dog.bark)))

    for obj in objects:
        print('{} {}'.format(str(obj), obj.speak()))

装饰者模式

title

  • 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活

  • 适用性:

    1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
    2. 处理那些可以撤消的职责
    3. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类
# Component
class Drink:
    def get_name(self):
        raise NotImpementError

    def get_price(self):
        raise NotImpementError

# ConcreteComponent
class Coke(Drink):
    def __init__(self):
        self.name = "Coke"
        self.price = 4.5

    def get_name(self):
        return self.name

    def get_price(self):
        return self.price

# Decorator
class drinkDecorator:
    def get_name(self):
        raise NotImpementError

    def get_price(self):
        raise NotImpementError

# ConcreteDecorator
class iceDecorator(drinkDecorator):
    def __init__(self, beverage):
        self.beverage = beverage

    def get_name(self):
        return self.beverage.get_name() + " + ice"

    def get_price(self):
        return self.beverage.get_price() + 0.3

if __name__ == '__main__':
    cola = Coke()
    print("Name: {}".format(cola.get_name()))
    print("Price: {}".format(cola.get_price()))
    ice_cola = iceDecorator(cola)
    print("Name: {}".format(ice_cola.get_name()))
    print("Price: {}".format(ice_cola.get_price()))    

代理模式

title

  • 意图:为其他对象提供一种代理以控制对这个对象的访问

  • 适用性:在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式

class Worker:
    def work(self):
        print("Worker is working!")

class Proxy:
    def __init__(self):
        self.status = "Free"
        self.worker = None

    def work(self):
        print("Proxy checking for worker availability")
        if self.status == "Free":
            self.worker = Worker()
            self.worker.work()
        else:
            print("Worker is busy!")

if __name__ == '__main__':
    p = Proxy()
    p.work()
    p.status = "Busy"
    p.work() 

外观模式

title

  • 意图:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

  • 适用性:需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系

class SubSystemA:
    def show(self):
        print("SubSystemA")

class SubSystemB:
    def show(self):
        print("SubSystemB")

class Facade:
    def __init__(self):
        self.subSystemA = SubSystemA()
        self.subSystemB = SubSystemB()

    def showA(self):
        self.subSystemA.show()

    def showB(self):
        self.subSystemB.show()

if __name__ == '__main__':
    facade = Facade()
    facade.showA()
    facade.showB()

桥接模式

title

  • 意图:将抽象部分与它的实现部分分离,使它们都可以独立地变化

  • 适用性:

    1. 不希望在抽象和它的实现部分之间有一个固定的绑定关系

    2. 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge 模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充

class DrawAPI1:
    def draw_square(self, length, width):
        print('API1.square length: {}, width: {}'.format(length, width))

class DrawAPI2:
    def draw_square(self, length, width):
        print('API2.square length: {}, width: {}'.format(length, width))

class Square:
    def __init__(self, length, width, drawing_api):
        self.length = length
        self.width = width
        self.drawing_api = drawing_api

    def draw(self):
        self.drawing_api.draw_square(self.length, self.width)

if __name__ == '__main__':
    shapes = (Square(1, 2, DrawAPI1()),
              Square(3, 4, DrawAPI2()))

    for shape in shapes:
        shape.draw()

组合模式

title

  • 意图:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite 模式使得用户对单个对象和组合对象的使用具有一致性

  • 适用性:

    1. 表示对象的部分-整体层次结构

    2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象

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

    def add(self, obj):
        pass

    def remove(self, obj):
        pass

    def display(self, level):
        pass

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

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

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

    def display(self, level=1):
        print("Department: {} Level: {} Duty: {}\n".format(self.name, level, self.duty))
        level = level + 1
        for obj in self.children:
            obj.display()

if __name__ == '__main__':
    root = Node("General Manager Office", "General Manager")
    node1 = Node("Financial Department", "Financial Manager")
    root.add(node1)
    node2 = Node("Operating Department", "Business Manager")
    root.add(node2)
    node3 = Node("Sales Department", "Sales Manager")
    node2.add(node3)

    root.display()

享元模式

title

  • 意图:运用共享技术有效地支持大量细粒度的对象

  • 适用性:

    1. 一个应用程序使用了大量的对象

    2. 完全由于使用大量的对象,造成很大的存储开销

    3. 对象的大多数状态都可变为外部状态

    4. 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象

    5. 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值

class Website:
    def use(self):
        pass

class ConcreteWebsite(Website):
    def __init__(self, name):
        self.name = name

    def use(self):
        print("Website Category: {}".format(self.name))

class UnsharedConcreteWebsite(Website):
    def __init__(self, name):
        self.name = name

    def use(self):
        print("Unshared Website Category: {}".format(self.name))

class FlyWeightFactory:
    def __init__(self):
        self.table = dict()

    def get_website(self, key):
        if not key in self.table:
            print("instantiate {}".format(key))
            self.table[key] = ConcreteWebsite(key)
        return self.table[key]

if __name__ == '__main__':
    factory = FlyWeightFactory()
    f1 = factory.get_website("blog")
    f2 = factory.get_website("blog")
    f3 = factory.get_website("website")
    f4 = UnsharedConcreteWebsite("test")

    f1.use()
    f2.use()
    f3.use()
    f4.use()