赞同 0
分享

【设计模式】- 构造、工厂、适配

简介:构造器模式、工厂模式、适配器模式 根据我自己的一些经验和想法通过Python代码带入到场景中实现这些设计模式。
  2021.04.09
  Bug Man
  0
  74
  172.17.0.1
  中国.上海
 
 

构造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。菜鸟教程

如果你使用过的插件比较多,可能你已经见过这种构造者模式了,下面我就模拟一下前端图形渲染插件构造者模式的写法。这里我用到了抽象类的写法,关于抽象类在强类型编程语言(Java)中可能比较经常会提到,在学习Python抽象类时你应该去看一看与抽象类有一丝丝关联的鸭子类型

在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。Python与鸭子类型

from abc import abstractmethod, ABC


class Build(ABC):
    """ 构造模式超类 """

    @abstractmethod
    def draw_overview(self):
        pass

    @abstractmethod
    def draw_details(self):
        pass


class MaxLayer(Build):
    """ 构造大图层 """

    def __init__(self):
        self.name = 'Max'

    def draw_overview(self):
        print(f'{self.name} 画轮廓')

    def draw_details(self):
        print(f'{self.name} 画细节')


class MinLayer(Build):
    """ 构造小图层 """

    def __init__(self):
        self.name = 'Min'

    def draw_overview(self):
        print(f'{self.name} 画轮廓')

    def draw_details(self):
        print(f'{self.name} 画细节')


class ContainerBuilder(object):
    """ 容器构造器 """

    def __init__(self, layer_list: list):
        sort_layer_list = list()
        for layer in layer_list:
            assert isinstance(layer, Build), 'This `layer` variable must be a subclass of the `Build` class.'
            # 优先画大图层
            if isinstance(layer, MaxLayer):
                sort_layer_list.insert(0, layer)
            else:
                sort_layer_list.append(layer)
        self.layer_list = sort_layer_list

    def draw(self):
        """ 开始构造 """
        for layer in self.layer_list:
            layer.draw_overview()
            layer.draw_details()


if __name__ == '__main__':
    max_layer = MaxLayer()
    min_layer = MinLayer()
    container = ContainerBuilder(layer_list=[max_layer, min_layer])
    container.draw()
    # Max 画轮廓
    # Max 画细节
    # Min 画轮廓
    # Min 画细节
工厂模式

工厂模式就是在不向用户展示创建逻辑的前提下,根据用户的需求创建并返回对应的对象。大多时候我们可以在多种有限场景下使用工厂模式,如果场景没有确定的数量但行为有确定的行为,这个时候我认为可以使用之前在单例模式中提到的type元类来做动态创建class类的操作并实例化成对象。

class Criminal(object):
    def __init__(self):
        self.name = '张三'

    def shopping(self):
        print(f'{self.name}挑选满意的商品!')
        print(f'{self.name}拿着商品就跑!')
        print(f'{self.name}被判刑!')


class Populace(object):
    def __init__(self):
        self.name = '李四'

    def shopping(self):
        print(f'{self.name}挑选满意的商品!')
        print(f'{self.name}收银台付款!')
        print(f'{self.name}回家路上扶老奶奶过马路!')


class Reincarnation(object):
    def get_person(self, select_type: str = ''):
        if select_type == 'populace':
            return Populace()
        else:
            return Criminal()


if __name__ == '__main__':
    reincarnation = Reincarnation()
    person = reincarnation.get_person('populace')
    person.shopping()
    person2 = reincarnation.get_person()
    person2.shopping()
    # 李四挑选满意的商品!
    # 李四收银台付款!
    # 李四回家路上扶老奶奶过马路!
    # 张三挑选满意的商品!
    # 张三拿着商品就跑!
    # 张三被判刑!
适配器模式(结构性模式)

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

提到这个适配我第一时间想到的就是我曾经做过类似的事情,就是多个后端语言的迁移数据库表的字段命名风格不一致的问题。这样就可以利用适配器模式的思维方式来做一个适配器,所有适配的工作有适配器完成,使用者只需要关注自己需要获取哪个数据库里面的数据和自己想要获得的命名风格。下面我就模拟了一下这种场景下适配器模式的用法。

from copy import deepcopy


class QueryData(object):
    """ 本地数据库查询类 """

    def __init__(self):
        self.where = {'inner_ip': '127.0.0.1', 'outer_ip': '56.18.29.23'}

    def query(self) -> dict:
        # 省略查询逻辑
        return QueryData.translate_interval(deepcopy(self.where))

    @classmethod
    def translate_interval(cls, target: dict) -> dict:
        result_dict = dict()
        for key, value in target.items():
            new_key = ''
            for i, k in enumerate(key.split('_')):
                if i == 0:
                    new_key += k
                    continue
                k = str.upper(k[0]) + k[1:]
                new_key += k
            result_dict[new_key] = value

        return result_dict


class RemoteQueryData(object):
    """ 远端数据库查询类 """

    def __init__(self):
        self.where = {'innerIp': '127.0.0.1', 'outerIp': '56.18.29.23'}

    def query(self) -> dict:
        # 省略查询逻辑
        return QueryData.translate_interval(deepcopy(self.where))


class QueryAdapter(object):
    """ 查询适配器 """
    adapter = None

    def __init__(self, terminal: str = 'local'):
        if terminal == 'local':
            self.adapter = QueryData()
        else:
            self.adapter = RemoteQueryData()

    def query(self) -> dict:
        """ 查询 """
        return self.adapter.query()


if __name__ == '__main__':
    query_adapter = QueryAdapter()
    print(query_adapter.query())
    query_adapter = QueryAdapter('remote')
    print(query_adapter.query())
    # {'innerIp': '127.0.0.1', 'outerIp': '56.18.29.23'}
    # {'innerIp': '127.0.0.1', 'outerIp': '56.18.29.23'}