zoukankan      html  css  js  c++  java
  • 设计模式之工厂模式

    一、理解工厂模式

      在工厂设计模式中,客户端可以请求一个对象,而无需知道这个对象来自哪里,它只需要知道需要传递的接口、方法和参数,就能够创建所需类型的对象了。这简化了客户端

    的实现。工厂模式具有松耦合(对象的创建独立于类的实现)、重用现有对象的特点。

      工厂模式有三种变体:

    •  简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑。
    • 工厂方法模式:允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的。
    • 抽象工厂模式:抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。

    一、简单工厂模式

      假设现在有一个果园种植了很多水果,假设现在生产苹果以及梨子的实例,一般情况会这样生产,创建了苹果以及梨子的类,并且分别进行实例。

    class Apple:
    
        def __init__(self):
            pass
    
    class Pear:
    
        def __init__(self):
            pass
    
    apple=Apple()
    pear=Pear()

      但是实际上这样是很麻烦的,此时可以利用简单工厂,根据客户端传递过来的参数,生产不同的水果实例。在下面中先创建一个水果的基类,用于保存水果的共同属性,然后每一个水果类继承这个基类,最后创建生产水果的工厂,根据客户端传递的参数生产相应的水果。

    from abc import ABCMeta,abstractmethod
    class Fruits(metaclass=ABCMeta):
        """
        水果基类,用于保存水果的共同属性
        """
        @abstractmethod
        def color(self):
            pass
    
        @abstractmethod
        def appearance(self):
            pass
    
    class Apple(Fruits):
    
        def color(self):
            print("我是青色的苹果")
    
        def appearance(self):
            print("我是圆形的苹果")
    
    
    class Pear(Fruits):
    
        def color(self):
            print("我是黄色的梨子")
    
        def appearance(self):
            print("我是圆形的梨子")
    
    class FruitsFactory:
        """
        水果工厂
        """
        def produce(self,fruit_type):
            if fruit_type=="Apple":
                return Apple()
            elif fruit_type=="Pear":
                return Pear()
            else:
               pass
    
    
    fruitsfactory=FruitsFactory()
    apple=fruitsfactory.produce("Apple")
    apple.color()
    apple.appearance()
    pear=fruitsfactory.produce("Pear")
    pear.color()
    pear.appearance()

    二、工厂方法模式

      虽然上面能够使创建实例变的简单,但是如果新增加一种水果草莓的话,那是不是就意味着必须新增加一个草莓类以及需要修改简单工厂的逻辑判断,很明显这违背了代码的开放封闭原则,这是不可行的,因此,引入了工厂方法模式。如果每一中水果由它们自己的工厂来生产就行了。

    from abc import ABCMeta,abstractmethod
    
    class Fruits(metaclass=ABCMeta):
        """
        水果基类,用于保存水果的共同属性
        """
        @abstractmethod
        def color(self):
            pass
    
        @abstractmethod
        def appearance(self):
            pass
    
    class Apple(Fruits):
    
        def color(self):
            print("我是青色的苹果")
    
        def appearance(self):
            print("我是圆形的苹果")
    
    
    class Pear(Fruits):
    
        def color(self):
            print("我是黄色的梨子")
    
        def appearance(self):
            print("我是圆形的梨子")
    
    class BaseFactory(metaclass=ABCMeta):
        """
        保存工厂的共有属性
        """
        def __init__(self):
            self.produce() 
    
        @abstractmethod
        def produce(self):
            pass
    
        def ready(self):
            print("完成生产对象准备工作")
    
    class AppleFactory(BaseFactory):
    
        def produce(self):
            self.ready()
            return Apple()
    
    class PearFactory(BaseFactory):
    
        def produce(self):
            self.ready()
            return Pear()
    
    AppleFactory() #如果没有init方法可以使用AppleFactory().produce()
    PearFactory()

    这样的话每个工厂负责生产自己的产品,避免了在新增产品时需要修改工厂的代码,而只要增加相应的工厂即可。由此得知:

    • 定义了一个接口来创建对象,但是工厂本身并不负责创建对象,而是将这一任务交由子类来完成,即子类决定了要实例化哪些类。
    • 工厂方法的创建是通过继承而不是通过实例化来完成的。
    • 工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类。

    三、抽象工厂模式 

      虽然上面解决了每一种产品都由自己的工厂来生产,但是如果有很多产品,比如现在又需要生产果汁的话,这是不是就意味着需要创建很多果汁工厂呢?那么如何解决这个问题呢?此时需要使用抽象工厂模式,只需要让相应的工厂生产同一类的多个产品。

    from abc import ABCMeta,abstractmethod
    
    class Fruits(metaclass=ABCMeta):
        """
        水果基类,用于保存水果的共同属性
        """
        @abstractmethod
        def color(self):
            pass
    
        @abstractmethod
        def appearance(self):
            pass
    
    class Apple(Fruits):
    
        def color(self):
            print("我是青色的苹果")
    
        def appearance(self):
            print("我是圆形的苹果")
    
    class Pear(Fruits):
    
        def color(self):
            print("我是黄色的梨子")
    
        def appearance(self):
            print("我是圆形的梨子")
    
    class Juice(metaclass=ABCMeta):
        """
        果汁基类,用于保存果汁的共同属性
        """
        @abstractmethod
        def marteria(self):
            pass
    
    class AppleJuice(Juice):
    
        def marteria(self):
            print("我的原料是苹果")
    
    
    class PearJuice(Juice):
    
        def marteria(self):
            print("我的原料是梨子")
    
    
    class BaseFactory(metaclass=ABCMeta):
        """
        保存工厂的共有属性
        """
        @abstractmethod
        def producefruit(self):
            pass
    
        @abstractmethod
        def producejuice(self):
            pass
    
        def ready(self):
            print("完成生产对象准备工作")
    
    class AppleFactory(BaseFactory):
    
        def producefruit(self):
            """
            生产产品苹果
            :return:
            """
            self.ready()
            return Apple()
    
        def producejuice(self):
            """
            生产产品苹果汁
            :return:
            """
            return AppleJuice()
    
    class PearFactory(BaseFactory):
    
        def producefruit(self):
            """
            生产产品梨子
            :return:
            """
            self.ready()
            return Pear()
    
        def producejuice(self):
            """
            生产产品梨子汁
            :return:
            """
            return PearJuice()
    
    AppleFactory().producefruit()
    AppleFactory().producejuice()
    PearFactory().producefruit()
    PearFactory().producejuice()

      可以看到又增加了果汁类产品,此时只需要让相应的工厂多增加一个生产果汁对象的方法即可,比如苹果工厂就让苹果工厂增加一个producejuice的方法,抽象工厂模式适用于多个对象的创建。

    from abc import ABCMeta,abstractmethod
    
    class Fruits(metaclass=ABCMeta):
        """
        水果基类,用于保存水果的共同属性
        """
        @abstractmethod
        def color(self):
            pass
    
        @abstractmethod
        def appearance(self):
            pass
    
    class Apple(Fruits):
    
        def color(self):
            print("我是青色的苹果")
    
        def appearance(self):
            print("我是圆形的苹果")
    
    class Pear(Fruits):
    
        def color(self):
            print("我是黄色的梨子")
    
        def appearance(self):
            print("我是圆形的梨子")
    
    class Juice(metaclass=ABCMeta):
        """
        果汁基类,用于保存果汁的共同属性
        """
        @abstractmethod
        def marteria(self):
            pass
    
    class AppleJuice(Juice):
    
        def marteria(self):
            print("我的原料是苹果")
    
    
    class PearJuice(Juice):
    
        def marteria(self):
            print("我的原料是梨子")
    
    
    class BaseFactory(metaclass=ABCMeta):
        """
        保存工厂的共有属性
        """
        @abstractmethod
        def producefruit(self):
            pass
    
        @abstractmethod
        def producejuice(self):
            pass
    
        def ready(self):
            print("完成生产对象准备工作")
    
    class AppleFactory(BaseFactory):
    
        def producefruit(self):
            """
            生产产品苹果
            :return:
            """
            self.ready()
            return Apple()
    
        def producejuice(self):
            """
            生产产品苹果汁
            :return:
            """
            return AppleJuice()
    
    class PearFactory(BaseFactory):
    
        def producefruit(self):
            """
            生产产品梨子
            :return:
            """
            self.ready()
            return Pear()
    
        def producejuice(self):
            """
            生产产品梨子汁
            :return:
            """
            return PearJuice()
    
    class Manufacturer:
    
        def __init__(self):
            pass
    
        def makejuice(self):
            for factory in [AppleFactory(),PearFactory()]:
                self.factory=factory
                self.fruit=self.factory.producefruit()
                self.juice=self.factory.producejuice()
    
    m=Manufacturer().makejuice()
    组合方式生产果汁

    四、总结

    工厂方法 抽象工厂方法

    它向客户端开放了一个创建对象的方法

    抽象工厂方‘法包含一个或多个工厂方法来创建一
    个系列的相关对象

    使用继承和子类来决定要创建哪个对象

    使用组合将创建对象的仃务委托给其他类
    工厂方法用于创建一个产品 抽象工厂方法用于创建产品系列

     参考书籍:python设计模式第2版

  • 相关阅读:
    TransformAroundPointPlugin
    探讨VMP 2.12.3 导入表修复
    spring+quartz 实现定时任务二
    一个奇怪的sql异常
    php程序里面使用sudo来执行应用程序
    spring+quartz 实现定时任务一
    让Git忽略SSL证书错误技巧
    个人开发网站集合
    完美解决KMplayer无法播放RMVB、RM电影问题
    如何知道自己的Windows是否已激活? 如何实现免激活升级? 重装Windows不需再激活?
  • 原文地址:https://www.cnblogs.com/shenjianping/p/11074439.html
Copyright © 2011-2022 走看看