zoukankan      html  css  js  c++  java
  • 设计模式之单例模式与工厂模式的Python实现(二)

    2. 工厂模式

    工厂模式是创建型设计模式的一种。核心的思想是,通过传递给类或函数某种产品的信息来创建产品并返回。当我们想得到产品a对象,只需把产品a的名字传递给工厂函数就能得到产品a对象。而核心思想的背后是为了遵循著名的“开闭原则”:对扩展开放,对修改封闭。当添加新功能时,对已经有的函数代码不需要修改,只需要添加新功能相关的代码即可。

    举一个最简单的例子:假如我们要写一个计算器,实现加减乘除四则运算,那么最简单的方法就是写一个函数,传入运算符,然后通过switch语句(python中没有switch语句,可以想办法用字典dict代替)。但问题也是显而易见的,如果我们要添加一个新的运算,比如开平方,那么就要修改原来的包含了四则运算的函数,显然,在这个过程中容易发生错误的修改,比如不小心改到了加法运算,这会让我们原先写好的功能有被修改错误的风险。所以,对应到这个问题上,工厂模式的核心就是要把这几个运算给完全独立出来,并且不影响运算主函数(即当添加新的运算时,我们不需要修改运算主函数)。怎么做呢?其实就是创建一个工厂类,由这个工厂类通过判断传入的运算符,去对应实例化各个运算函数(或者运算类)。这样,当添加了新的运算时,我们只需要添加新的运算函数(或者运算类),和修改工厂类(即添加新的switch判断,实例化新的运算函数或者运算类)就可以了。

    2.1 简单工厂模式

    简单工厂模式,是最简单的工厂方法模式,其由两部分组成,一是:工厂函数或工厂类,二是:产品类(可以是多个产品类A,B,C.........)。

    下面我们通过一个简单的例子来看什么是简单工厂模式:

    class A(object):
        def __init__(self, product_type):
            self.product_type = product_type
     
        def __str__(self):
            return 'product %s' % self.product_type
     
     
    class B(object):
        def __init__(self, product_type):
            self.product_type = product_type
     
        def __str__(self):
            return 'product %s' % self.product_type
     
     
    class Factory(object):
        @staticmethod
        def yield_product(product_type):
            if product_type == 'A':
                return A(product_type)
            if product_type == 'B':
                return B(product_type)
     
    if __name__ == '__main__':
        a = Factory.yield_product('A')
        b = Factory.yield_product('B')
        print(a)
        print(b)

    结果如下

    product A
    product B

    上面代码中,实现了两个产品类A,B,一个工厂类Factory,工厂类中实现了一个静态方法,其实,可以用一个工厂函数来代替这个工厂类。静态方法可以通过类名进行调用,而不需把类实例化。

    静态方法@staticmethod的意思是,这个方法是一个普通方法,虽然属于类,但是不用访问类的其他成员。并且可以在不把类实例化的前提下,通过类名进行调用

    2.2 工厂方法模式

    简单工厂模式存在一个问题,当要增加产品时,需要修改工厂类或者工厂方法,在上面的例子中,我们需要修改工厂类的方法"yield_product"这违背了扩展开放,修改封闭的原则,因此是不可取的。工厂方法模式能够实现最小化地修改工厂类或工厂函数。

    具体实现:对每一个产品类再进行一次封装,封装成只生产特定产品的工厂类。

    import abc
     
     
    class A(object):
        def __init__(self, product_type):
            self.product_type = product_type
     
        def __str__(self):
            return 'product %s' % self.product_type
     
     
    class B(object):
        def __init__(self, product_type):
            self.product_type = product_type
     
        def __str__(self):
            return 'product %s' % self.product_type
     
     
    class Abstract_factory(object):
        __metaclass__ = abc.ABCMeta
     
        @abc.abstractmethod
        def yield_product(self):
            pass
     
     
    class Factory_a(Abstract_factory):
     
        def yield_product(self):
            return A('A')
     
     
    class Factory_b(Abstract_factory):
     
        def yield_product(self):
            return B('B')
     
     
    def factory(product_type):
        if product_type == 'A':
            return Factory_a()
        if product_type == 'B':
            return Factory_b()
     
    if __name__ == '__main__':
        factory_a = factory('A')
        a = factory_a.yield_product()
        factory_b = factory('B')
        b = factory_b.yield_product()
        print(a)
        print(b)

    结果如下

    product A
    product B

    上述代码,Factory_a,Factory_b是对类A,B的封装,一个工厂只负责创建一个产品遵从了单一职责原则,有利于代码的扩展和维护。

    其中@abc.abstractmethod表示被该装饰器修饰的方法是一个抽象方法,没有实现,所以该基本不能被实例化。只有子类实现了该抽象方法才能被实例化。

    参考链接:

    1. python 设计模式(三) 工厂模式 https://blog.csdn.net/ruguowoshiyu/article/details/80657052

    2. Python中的staticmethod与classmethod

    3. python中@classmethod @staticmethod区别

    4. Python2和Python3中@abstractmethod的用法 https://blog.csdn.net/xiemanR/article/details/72629164

  • 相关阅读:
    C#中|(位或)和||(逻辑或)
    VS快捷键(转)
    C# 3.0 新特性 学习(二):匿名类型、扩展方法
    Highcharts 如何添加基准线
    怎样用Diskpart进行分区
    命名空间别名限定符 (::)
    NDK下 将Platinum SDK 编译成so库 (android upnp)
    在native线程利用JNI 反射自定义类
    GithubClient(ANDROID)开源之旅(一) 初探GitHub
    基于Platinum库的DMR实现(android)
  • 原文地址:https://www.cnblogs.com/ArsenalfanInECNU/p/9779424.html
Copyright © 2011-2022 走看看