最近在公司需要做一次技术分享,由于组内几乎全是 “Pythoner”,为了便于大家更好的理解,我只好硬着头皮看了看Python的基本语法,尝试着将分别用(Swift、Python)两种语言举例讲解,demo源码会在文章底部连接提供,下面步入正题。
目录
工厂模式分类:简单工厂、抽象工厂、工厂方法
一、简单工厂
定义: 是由一个工厂对象决定创建出哪一种产品类的实例。实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例。
角色分类:
- 工厂类角色(Creator):工厂类在客户端的直接控制下(Create方法)创建产品对象。
- 抽象产品角色(Product):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
- 具体产品角色(ConcreteProduct):定义工厂加工出的具体产品对象。
使用场景:
负责创建的对象比较少,创建产品对象的类别比较单一;客户只知道传入工厂类的参数,对于如何创建对象不关心。
优缺点:
优点:
- 工厂类是整个模式的关键,包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。有利于整个软件体系结构的优化。
缺点:
- 可扩展性有限,当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利 ,这些缺点在工厂方法模式中得到了一定的克服 。
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)
运行结果:
马老师喜欢吃香蕉
二、抽象工厂
定义: 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。抽象工厂模式针对的是多个产品等级结构。
角色分类:
- 抽象工厂类角色(Creator):定义具体工厂对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口
- 具体工厂类角色(Concrete Creator):定义具体工厂在客户端的直接控制下(Create方法)创建产品对象组。
- 抽象产品角色(Product):定义工厂创建的对象组中对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
- 具体产品角色(ConcreteProduct):定义工厂加工出的具体产品组中的对象。
使用场景:
- 一个系统应当不依赖于产品类实例被创立,组成,和表示的细节。这对于所有形态的工厂模式都是重要的。
- 这个系统的产品有多于一个的产品族。
- 同属于同一个产品族的产品是设计成在一起使用的。这一约束必须得在系统的设计中体现出来。
- 不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节。
优缺点:
优点:
- 抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。
- 当一个产品组中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
- 增加新的具体工厂和产品组很方便,无须修改已有系统,符合“开闭原则”。
缺点:
- 增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。
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)使一个类的实例化延迟到其子类。
角色分类:
- 抽象工厂类角色(Creator):Creator是生产产品的工厂对象抽象基类。Creator提供创建虚方法即工厂方法FactoryMeothod()。FactoryMeothod()由派生ConcreteCreator)具体实现,生产对应的具体产品(ConcreteProduct)。Creator不必关心产品的具体生产方法。
- 具体工厂类角色(ConcreteCreator): ConcreteCreator是生产对应具体产品(ConcreteProduct)的具体工厂。它重新实现继承的工厂方法FactoryMeothod(),生产具体产品。
- 抽象产品角色(Product):Product是工厂方法生产产品的抽象基类。
- 具体产品角色(ConcreteProduct):ConcreteProduct是继承Product的具体产品。
使用场景:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。(往往放在抽象产品侧)。
要点:
- 工厂方法模式中,工厂和产品的基类和派生类是平行关系。抽象产品(Product)对应层次是抽象工厂(Creator)。在派生类层次,每个具体产品(ConcreteProduct)对应一个具体工厂(ConcreteCreator)。换句话说,每新增一个具体产品,就要新增一个对应的具体工厂。
- 工厂方法的核心是FactoryMeothod(),每个具体工厂都重新实现该接口,产生具体类对象。
- 工厂方法分离客户端和具体类的实现。利用子类(即具体工厂),让子类来决定如何来生产一个具体产品。这样,客户端(即调用者)只需要知道这个类的抽象类型,由子类去和具体产品类打交道。
- 工厂基类中的方法AnOperation(),不是工厂方法,只是供具体工厂实现的公共接口(可以说是工厂对产品的使用行为)。但个人认为,工厂方法只是生产产品,公共接口的重点应该是产品,因此在产品基类里增加产品使用的公共接口更加实用。
优缺点:
优点:
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,正是因为所有的具体工厂类都具有同一抽象父类。
缺点:
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。产品过多时会大大增加维护成本。
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代码下载链接: