python 设计模式-简单工厂

工厂模式也是最常用的设计模式之一,可以分为简单工厂、工厂方法、抽象工厂三大类型,简单工厂模式不属于GOF。这里就python中简单工厂的实现做个简单说明,我们从最普通的实现一步一步优化。先看代码:

#!/usr/bin/env python
#coding: utf-8

class DesktopPC:
    pass


class AllInOnePC:
    pass


class Laptop:
    pass


class PcSimpleFactory:

    def produce(self, category):
        product = None
        if category == 'desktop':
            product = Desktop()
        elif category == 'all_in_one':
            product = AllInOnePC()
        elif category == 'laptop':
            product = Laptop()
        else:
            pass
        return product


if __name__:
    p = PcSimpleFactory()
    print(p.produce('desktop'))
    print(p.produce('all_in_one'))
    print(p.produce('laptop'))

输出

<__main__.DesktopPC object at 0x7f2447720390>
<__main__.AllInOnePC object at 0x7f2447720390> 
<__main__.Laptop object at 0x7f2447720390>

在其他面向对象的高级语言中,我们经常看到产品会专门抽象出来一个接口,所有具体产品实现该接口。由于python是鸭子类型(ducking type,如果它走路像鸭子,游泳像鸭子,那么我们就认为它是鸭子; ),似乎接口就没有没什么存在的必要了,如果开发人员都能够严格遵守规范,确实没有必要了。但有时候为了避免开发人员由于粗心犯错,我们有必要在程序层面强制当前类必须实现特定方法,python在语言层面没有这种支持,不过在标准库abc里提供了抽象类的功能,继承抽象类的类必须实现抽象类中的方法。代码修改如下:

from abc import ABCMeta, abstractmethod


class PC(metaclass=ABCMeta):
    @abstractmethod
    def run():
        pass


class DesktopPC(PC):
    def run():
        print('this is run on DesktopPC')


class AllInOnePC(PC):
    def run():
        print('this is run on AllInOnePC')


class Laptop(PC):
    def run():
        print('this is run on Laptop')

这样只要是PC,我们都继承PC这个抽象类,就不会漏掉他应该实现的方法了。再看看有没有什么可以优化的地方,前面文章里我们介绍了单例模式,不正是为工厂量身定制的嘛,再修改:

from weakref import WeakValueDictionary
from abc import ABCMeta, abstractmethod


class SingletonBase:
    _instance = WeakValueDictionary()
    def __new__(cls, *args, **kwargs):
        return cls._instance.setdefault(cls, super(SingletonBase, cls).__new__(cls))


class PC(metaclass=ABCMeta):
    @abstractmethod
    def run():
        pass


class DesktopPC(PC):
    def run():
        print('this is run on DesktopPC')


class AllInOnePC(PC):
    def run():
        print('this is run on AllInOnePC')


class Laptop(PC):
    def run():
        print('this is run on Laptop')


class PcSimpleFactory(SingletonBase):

    def produce(self, category):
        product = None
        if category == 'desktop':
            product = DesktopPC()
        elif category == 'all_in_one':
            product = AllInOnePC()
        elif category == 'laptop':
            product = Laptop()
        else:
            pass
        return product

看着似乎不差,好像还不够完美,我们试着使用python的特性修改下他:

#!/usr/bin/env python
#coding: utf-8

from weakref import WeakValueDictionary
from abc import ABCMeta, abstractmethod

class SingletonBase:
    _instance = WeakValueDictionary()
    def __new__(cls, *args, **kwargs):
        return cls._instance.setdefault(cls, super(SingletonBase, cls).__new__(cls))


class PC(metaclass=ABCMeta):
    @abstractmethod
    def run():
        pass


class DesktopPC(PC):
    def run():
        print('this is run on DesktopPC')


class AllInOnePC(PC):
    def run():
        print('this is run on AllInOnePC')


class Laptop(PC):
    def run():
        print('this is run on Laptop')


class PcSimpleFactory(SingletonBase):
    def __init__(self, producesMap=None):
        self._produceMap = producesMap

    def produce(self, category):
        return self._produceMap[category]()


if __name__:
    p = PcSimpleFactory({'desktop': DesktopPC, 'all_in_one': AllInOnePC, 'laptop': Laptop})
    print(p.produce('desktop'))
    print(p.produce('all_in_one'))
    print(p.produce('laptop'))

我们使用字典替代了丑陋的if/else,看起来舒服多了,但是好像还有个问题,万一使用的人传进去的producesMap中的产品类型不对呢,我们加个检测:

#!/usr/bin/env python
#coding: utf-8

from weakref import WeakValueDictionary
from abc import ABCMeta, abstractmethod

class SingletonBase:
    _instance = WeakValueDictionary()
    def __new__(cls, *args, **kwargs):
        return cls._instance.setdefault(cls, super(SingletonBase, cls).__new__(cls))


class PC(metaclass=ABCMeta):
    @abstractmethod
    def run():
        pass

class DesktopPC(PC):
    def run():
        print('this is run on DesktopPC')


class AllInOnePC(PC):
    def run():
        print('this is run on AllInOnePC')


class Laptop(PC):
    def run():
        print('this is run on Laptop')


class PcSimpleFactory(SingletonBase):
    def __new__(cls, *args, **kwargs):
        if any((not issubclass(v, PC) for _, v in args[0].items())):
            raise Exception('pc map error')
        return super(PcSimpleFactory, cls).__new__(cls, *args, **kwargs)

    def __init__(self, producesMap=None):
        self._produceMap = producesMap

    def produce(self, category):
        return self._produceMap[category]()



if __name__:
    p = PcSimpleFactory({'desktop': DesktopPC, 'all_in_one': AllInOnePC, 'laptop': Laptop})
    print(p.produce('desktop'))
    print(p.produce('all_in_one'))
    print(p.produce('laptop'))

现在应该差不多了,完美

你可能感兴趣的:(python)