工厂方法模式(Swift、Python 双版)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012903898/article/details/82188813

最近在公司需要做一次技术分享,由于组内几乎全是 “Pythoner”,为了便于大家更好的理解,我只好硬着头皮看了看Python的基本语法,尝试着将分别用(Swift、Python)两种语言举例讲解,demo源码会在文章底部连接提供,下面步入正题。

目录

工厂模式分类:简单工厂、抽象工厂、工厂方法

一、简单工厂

二、抽象工厂

三、工厂方法模式


工厂模式分类:简单工厂、抽象工厂、工厂方法

一、简单工厂

定义: 是由一个工厂对象决定创建出哪一种产品类的实例。实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例。

角色分类:

  1. 工厂类角色(Creator):工厂类在客户端的直接控制下(Create方法)创建产品对象。
  2. 抽象产品角色(Product):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
  3. 具体产品角色(ConcreteProduct):定义工厂加工出的具体产品对象。

使用场景:

负责创建的对象比较少,创建产品对象的类别比较单一;客户只知道传入工厂类的参数,对于如何创建对象不关心。

优缺点:

优点:

  1. 工厂类是整个模式的关键,包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。有利于整个软件体系结构的优化。

缺点:

  1. 可扩展性有限,当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利 ,这些缺点在工厂方法模式中得到了一定的克服 。

Demo举例

下面编写一个水果工厂的例子来说明

工厂类角色:FruitGenerator

Swift:

class FruitGenerator: NSObject {
    //水果类型
    enum FruitType{
        case Apple
        case  Banana
    }
    
    func produceFruit(fruitType:FruitType) -> Fruit{
        switch fruitType {
        case .Apple:
            return Apple()
        case .Banana:
            return Banana()
        }
        
    }
}

Python:

class FruitGenerator(object):
    def produceFruit(self,fruitType):
        dicFruitType = {
            0: Apple(),
            1: Banana()
        }
        return dicFruitType.get(fruitType,Fruit())

class FruitType(Enum):
    apple = 0
    banana = 1

 

抽象产品角色:Fruit

Swift:

class Fruit: NSObject {
    var name:String {
        return "水果"
    }
}

Python:

class Fruit(object):
    def getName(self):
        return "水果"

具体产品角色:Apple、Banana

Swift:

class Apple: Fruit {
    override var name: String{
        return "苹果"
    }
}

class Banana: Fruit {
    override var name: String{
        return "香蕉"
    }
}

Python:

class Apple(Fruit):
    def getName(self):
        return "苹果"

class Banana(Fruit):
    def getName(self):
        return "香蕉"

运行:

Swift:

override func viewDidLoad() {
        super.viewDidLoad()
        eatFruit(eatFruitType: FruitGenerator.FruitType.Banana)
    }

func eatFruit(eatFruitType: FruitGenerator.FruitType){
        let fruitGenerator = FruitGenerator()
        let fruit = fruitGenerator.produceFruit(fruitType: eatFruitType)
        let fruitName = fruit.name
        print("马老师喜欢吃吃:"+fruitName)
    }

Python:

def eatFruit(fruitType):
    fruit = FruitGenerator().produceFruit(fruitType)
    print "马老师喜欢吃"+ fruit.getName()


eatFruit(FruitType.banana)

运行结果:

马老师喜欢吃香蕉

 

二、抽象工厂

定义: 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。抽象工厂模式针对的是多个产品等级结构。

角色分类:

  1. 抽象工厂类角色(Creator):定义具体工厂对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口
  2. 具体工厂类角色(Concrete Creator):定义具体工厂在客户端的直接控制下(Create方法)创建产品对象组。
  3. 抽象产品角色(Product):定义工厂创建的对象组中对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
  4. 具体产品角色(ConcreteProduct):定义工厂加工出的具体产品组中的对象。

使用场景:

  1. 一个系统应当不依赖于产品类实例被创立,组成,和表示的细节。这对于所有形态的工厂模式都是重要的。  
  2. 这个系统的产品有多于一个的产品族。      
  3. 同属于同一个产品族的产品是设计成在一起使用的。这一约束必须得在系统的设计中体现出来。  
  4. 不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节。

优缺点:

优点:

  1. 抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。      
  2. 当一个产品组中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。      
  3. 增加新的具体工厂和产品组很方便,无须修改已有系统,符合“开闭原则”。

缺点:

  1. 增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。

Demo举例

下面编写一个餐饮工厂的例子来说明

抽象工厂类角色:FoodGenerator

Swift:

class FoodGenerator: NSObject {
    
    //食物类型
    enum FoodType{
        case ChineseFood
        case WesternFood
    }
    
    class func creatGenerator(foodType:FoodType) -> FoodGenerator {
        switch foodType {
        case FoodType.ChineseFood:
            return FoodAGenerator() as FoodGenerator
        case FoodType.WesternFood:
            return FoodBGenerator() as FoodGenerator
        }
    }
    
    func cookFood() -> NSDictionary {
        return NSDictionary()
    }

}

Python:

# 工厂类
class FoodGenerator(object):
class FoodGenerator(object):
    @classmethod
    def creatGenerator(cls,foodType):
        dicFoodType = {
            0: FoodAGenerator(),
            1: FoodBGenerator()
        }
        return dicFoodType.get(foodType,FoodGenerator())

    def cookFood(self):
        return {}

具体工厂类角色:FoodAGenerator、FoodBGenerator

Swift:

class FoodAGenerator: FoodGenerator {
    override func cookFood() -> NSDictionary {
        let drink = SoyaMilk()
        let food = DeepFried()
        let a = ["food":food.name,"drink":drink.name]
        return a as NSDictionary
    }
}

class FoodBGenerator: FoodGenerator {
    override func cookFood() -> NSDictionary {
        let drink = Coffee()
        let food = Hamburg()
        let a = ["food":food.name,"drink":drink.name]
        return a as NSDictionary
    }
}

Python:

class FoodAGenerator(FoodGenerator):
    def cookFood(self):
        soyaMilk = SoyaMilk()
        deepFried = DeepFried()
        return {"food":deepFried.getName(),"drink":soyaMilk.getName()}


class FoodBGenerator(FoodGenerator):
    def cookFood(self):
        coffee = Coffee()
        hamburg = Hamburg()
        return {"food":hamburg.getName(),"drink":coffee.getName()}

 

抽象产品角色:Drink、Food

Swift:

class Coffee: Drink {
    override var name: String{
        return "咖啡"
    }
}

class SoyaMilk: Drink {
    override var name: String{
        return "豆浆"
    }
}

Python:

#主食类
class Food(object):
    def getName(self):
        return "主食"

#饮品类
class Drink(object):
    def getName(self):
        return "饮品"

具体产品角色:(Drink):Coffee、SoyaMilk    (Food):Hamburg、DeepFried

Swift:

class Coffee: Drink {
    override var name: String{
        return "咖啡"
    }
}

class SoyaMilk: Drink {
    override var name: String{
        return "豆浆"
    }
}

class Hamburg: Food {
    override var name: String{
        return "汉堡"
    }
}

class DeepFried: Food {
    override var name: String{
        return "油条"
    }
}

Python:

class Coffee(Drink):
    def getName(self):
        return "咖啡"

class SoyaMilk(Drink):
    def getName(self):
        return "豆浆"


class Hamburg(Food):
    def getName(self):
        return "汉堡"

class DeepFried(Food):
    def getName(self):
        return "油条"

运行:

Swift:

override func viewDidLoad() {
        super.viewDidLoad()
        eatFood(mFoodType: FoodGenerator.FoodType.WesternFood)
    }
    
func eatFood(mFoodType:FoodGenerator.FoodType){
        let generator = FoodGenerator.creatGenerator(foodType: mFoodType)
        let meal = generator.cookFood()
        let food = meal.object(forKey: "food") as! String
        let drink = meal.object(forKey: "drink") as! String
        print("马老师吃着:" + food + ",喝着:" + drink)
    }

Python:

def eatFood(foodType):
    generator = FoodGenerator.creatGenerator(foodType)
    meal = generator.cookFood()
    foodName = meal["food"]
    drinkName = meal["drink"]
    print "马老师吃着:"+ foodName + ",喝着:" + drinkName

eatFood(FoodType.ChineseFood)

运行结果:

马老师吃着:油条,喝着:豆浆

三、工厂方法模式

定义: 一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法(Factory Method)使一个类的实例化延迟到其子类。

角色分类:

  1. 抽象工厂类角色(Creator):Creator是生产产品的工厂对象抽象基类。Creator提供创建虚方法即工厂方法FactoryMeothod()。FactoryMeothod()由派生ConcreteCreator)具体实现,生产对应的具体产品(ConcreteProduct)。Creator不必关心产品的具体生产方法。
  2. 具体工厂类角色(ConcreteCreator): ConcreteCreator是生产对应具体产品(ConcreteProduct)的具体工厂。它重新实现继承的工厂方法FactoryMeothod(),生产具体产品。
  3. 抽象产品角色(Product):Product是工厂方法生产产品的抽象基类。
  4. 具体产品角色(ConcreteProduct):ConcreteProduct是继承Product的具体产品。

使用场景:

  1. 当一个类不知道它所必须创建的对象的类的时候。
  2. 当一个类希望由它的子类来指定它所创建的对象的时候。
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。(往往放在抽象产品侧)。

要点:

  1.  工厂方法模式中,工厂和产品的基类和派生类是平行关系。抽象产品(Product)对应层次是抽象工厂(Creator)。在派生类层次,每个具体产品(ConcreteProduct)对应一个具体工厂(ConcreteCreator)。换句话说,每新增一个具体产品,就要新增一个对应的具体工厂。
  2.  工厂方法的核心是FactoryMeothod(),每个具体工厂都重新实现该接口,产生具体类对象。
  3. 工厂方法分离客户端和具体类的实现。利用子类(即具体工厂),让子类来决定如何来生产一个具体产品。这样,客户端(即调用者)只需要知道这个类的抽象类型,由子类去和具体产品类打交道。
  4. 工厂基类中的方法AnOperation(),不是工厂方法,只是供具体工厂实现的公共接口(可以说是工厂对产品的使用行为)。但个人认为,工厂方法只是生产产品,公共接口的重点应该是产品,因此在产品基类里增加产品使用的公共接口更加实用。

 

优缺点:

优点:

  1. 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。
  2. 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,正是因为所有的具体工厂类都具有同一抽象父类。

缺点:

  1. 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。产品过多时会大大增加维护成本。

Demo举例

下面编写一个汽车工厂的例子来说明

抽象工厂类角色:CarFactory

Swift:

class CarFactory: NSObject {
    func produceCar() -> Car {
        return Car()
    }
}

Python:

#工厂类
class CarFactory(object):
    def produceCar(self):
        return Car()

具体工厂类角色:CharadeFactory、FerrariFactory

Swift:

class CharadeFactory(CarFactory):
    def produceCar(self):
        return Charade()

class FerrariFactory(CarFactory):
    def produceCar(self):
        return Ferrari()

Python:

class FoodAGenerator(FoodGenerator):
    def cookFood(self):
        soyaMilk = SoyaMilk()
        deepFried = DeepFried()
        return {"food":deepFried.getName(),"drink":soyaMilk.getName()}


class FoodBGenerator(FoodGenerator):
    def cookFood(self):
        coffee = Coffee()
        hamburg = Hamburg()
        return {"food":hamburg.getName(),"drink":coffee.getName()}

 

抽象产品角色:Car

Swift:

class Car: NSObject {
    var name:String {
        return "汽车"
    }
}

Python:

#产品类
class Car(object):
    def getName(self):
        return "汽车"

具体产品角色:(Drink):Coffee、SoyaMilk    (Food):Hamburg、DeepFried

Swift:

class Charade: Car {
    override var name:String {
        return "夏利"
    }
}

class Ferrari: Car {
    override var name:String {
        return "法拉利"
    }
}

Python:

class Charade(Car):
    def getName(self):
        return "夏利"

class Ferrari(Car):
    def getName(self):
        return "法拉利"

运行:

Swift:

override func viewDidLoad() {
        super.viewDidLoad()
        let carFactory = CharadeFactory()
        buyCar(factory: carFactory)
    }

func buyCar(factory:CarFactory){
        let car = factory.produceCar() as Car
        print("马老师喜提:" + car.name)
        
    }

Python:

def buyCar(factory):
    car = factory.produceCar()
    print "马老师喜提:" + car.getName()


buyCar(FerrariFactory())

运行结果:

马老师喜提:法拉利

总结

工厂模式的应用场景非常广泛,在某些场景可以大大优化项目结构,理解工厂模式对于每个开发来说都是必不可少的。本菜能力有限,博客难免出现错误,如发现问题还请大神指出。下面附上demo代码下载链接:

工厂模式demo(swift、python双语版)下载

展开阅读全文

没有更多推荐了,返回首页