创建型模式-抽象工厂

使用场景:继承,创建各种子类对象,多种继承关系

意义:

隐藏了选择子类、创建子类对象的过程,隐藏各对象间的相互关系,简化对外接口

原理描述:

可以看作是多个工厂方法生产出各种类型对象后,这些毫无关系的对象,由抽象工厂方法联系起来。

具体使用:

1、平常使用的方式

创建一个名为AbstractFactory的OS X命令行工具项目。如上面说的,多种继承关系,下面就创建各种不同的协议、和继承协议的子类。首先创建第一个协议及子类Floorplans.swift

//协议
protocol Floorplan {
    var seats:Int{get}
    var enginePosition:EngineOption {get}
}

enum EngineOption:String {
    case FRONT = "Front";
    case MID = "Mid";
}
//协议继承的子类
class ShortFloorplan: Floorplan {
    var seats: Int = 2
    var enginePosition: EngineOption = EngineOption.MID
}

class StandardFloorplan: Floorplan {
    var seats: Int = 4
    var enginePosition: EngineOption = EngineOption.FRONT
}

class LongFloorplan: Floorplan {
    var seats: Int = 8
    var enginePosition: EngineOption = EngineOption.FRONT
}

第二个协议及子类Suspension.swift

protocol Suspension { 
    var suspensionType:SuspensionOption{get}
}

enum SuspensionOption:String {
   case STANDARD = "Standard";
   case SPORTS = "Firm";
   case SOFT = "Soft";
}

class RoadSuspension: Suspension {
    var suspensionType = SuspensionOption.STANDARD
}

class OffRoadSuspension: Suspension {
    var suspensionType: SuspensionOption = SuspensionOption.SOFT
}

class RaceSuspension: Suspension {
    var suspensionType: SuspensionOption = SuspensionOption.SPORTS
}

再创建第三个协议及子类Drivetrain.swift

protocol Drivetrain {
    var driveType:Driveoption{get}
}

enum Driveoption :String {
    case FRONT="Front";
    case REAR = "Rear";
    case ALL = "4WD";
}

class FrontWheelDrive: Drivetrain {
    var driveType: Driveoption = Driveoption.FRONT
}

class RearWheelDrive: Drivetrain {
    var driveType: Driveoption = Driveoption.REAR
}

class ALLWheelDrive: Drivetrain {
    var driveType: Driveoption = Driveoption.ALL
}

为了让三个协议之间有联系,创建CarsParts.swift

enum Cars:String {
    case COMPACT = "VM Golf";
    case SPORTS = "Porsche Boxter";
    case SUV = "Cadillac Escalade";
}
//由三种协议子类对象、Cars枚举,组成结构体Car
struct Car {
    var carType:Cars
    var floor:Floorplan
    var suspension:Suspension
    var drive:Drivetrain
    //提供各种属性的打印
    func pritDetails(){
        print("Car type:\(carType.rawValue)")
        print("Seats: \(floor.seats)")
        print("Engine:\(floor.enginePosition.rawValue)")
        print("Susension:\(suspension.suspensionType.rawValue)")
        print("Drive:\(drive.driveType.rawValue)")
    }
}

main.swift中使用是这样的:

var car = Car(carType:Cars.SPORTS,floor:ShortFloorplan(),suspension:RaceSuspension(),drive:RearWheelDrive())
car.pritDetails()
问题:创建结构体对象car时,用到了每个协议的具体实现方法,这样暴露出去的坏处在于,实现方法改变后,car的初始化方法也会改变。我们想,可不可以提供一个隐藏所有选择细节的方法?类似于这样var car = Car(carType:Cars.SPORTS)
2、实现抽象工厂
  • 创建抽象工厂类:
    创建Abstract.swift
    提供创建每个类型的方法,没有实现,由子类重写实现
class CarFatory{

    func createFloorplan() -> Floorplan {
        fatalError("Not implemented")
    }
    
    func creatSuspension() -> Suspension {
        fatalError("Not implemented")
    }
    
    func creatDrivetrain() -> Drivetrain {
        fatalError("Not implemented")
     }
  }
  • 具体工厂类
    创建Concrete.swift
    继承抽象工厂,重写创建方法,实现每个类型具体创建
class CompactCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return StandardFloorplan()
    }
    override func creatSuspension() -> Suspension {
        return RoadSuspension()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return FrontWheelDrive()
    }
}

class SportsCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return ShortFloorplan()
    }
    
    override func creatSuspension() -> Suspension {
        return RaceSuspension()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return ALLWheelDrive()
    }
}

class SUVCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return LongFloorplan()
    }
    
    override func creatSuspension() -> Suspension {
        return OffRoadSuspension()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return ALLWheelDrive()
    }
}

抽象工厂类应该是漏了一个选择的逻辑,根据类型选择合适的工厂方法。于是在Abstract.swift需要添加如下:

 final class func getFactory(car:Cars) -> CarFatory?{
    
        var factoryType:CarFatory?
        switch car {
        case .COMPACT:
            factoryType = CompactCarFactory()
        case .SPORTS:
            factoryType = SportsCarFactory()
        case .SUV:
            factoryType = SUVCarFactory()
        }
        return factory
    }

于是main.swift现在使用起来是这样的:

let factory = CarFatory.getFactory(car: Cars.SPORTS)

if (factory != nil){
    let car = Car(carType:Cars.SPORTS,floor:factory.createFloorplan(),suspension:factory.creatSuspension(),drive:factory.creatDrivetrain())
    car.pritDetails()
}

现在虽然没有暴露选择细节,但是调用组件的细节暴露出来,干脆把调用组件也隐藏起来。

于是在CarParts.swift中添加init方法把调用组件的细节加进去。

enum Cars:String {
    case COMPACT = "VM Golf";
    case SPORTS = "Porsche Boxter";
    case SUV = "Cadillac Escalade";
}

struct Car {
    var carType:Cars
    var floor:Floorplan
    var suspension:Suspension
    var drive:Drivetrain
   //把调用组件的细节放在初始化过程 
    init(carType:Cars) {
        let concreteFactory = CarFatory.getFactory(car: carType)
        self.floor = (concreteFactory?.createFloorplan())!
        self.suspension = (concreteFactory?.creatSuspension())!
        self.drive = (concreteFactory?.creatDrivetrain())!
        self.carType = carType
    }
    
    
    func pritDetails(){
        print("Car type:\(carType.rawValue)")
        print("Seats: \(floor.seats)")
        print("Engine:\(floor.enginePosition.rawValue)")
        print("Susension:\(suspension.suspensionType.rawValue)")
        print("Drive:\(drive.driveType.rawValue)")
    }
}

至此抽象工厂已经完整实现,我们捋一捋思路:

1、在干什么:

创建一个车car,car必须由三部分组成:FloorplanSuspensionDrivetrain。而这三部分都有各自的子类,通过不同的子类组合就有了carType。那么抽象工厂解决的就是谁去创建这三部分子类、谁去组装子类。

2、该怎么干:

大体分两个步骤,一个抽象工厂类、一个具体工厂类。抽象工厂类提供创建子类的方法,由具体工厂类继承实现;抽象工厂还有一个对外提供选择的接口,根据外界条件生成具体工厂类。

屏幕快照 2017-03-31 00.32.03.png

以下为选读

3、抽象工厂和其他模式结合的场景:
3.1、结合单例模式:

首先改动一下抽象工厂Abstract.swift

class CarFatory{
    
    //避免下面创建factoryType.init()报错
    required init() {
    
    }
    
    func createFloorplan() -> Floorplan {
        fatalError("Not implemented")
    }
    
    func creatSuspension() -> Suspension {
        fatalError("Not implemented")
    }
    
    func creatDrivetrain() -> Drivetrain {
        fatalError("Not implemented")
    }
    
    final class func getFactory(car:Cars) -> CarFatory?{
        //使用元类
        var factoryType:CarFatory.Type
        switch car {
        case .COMPACT:
            factoryType = CompactCarFactory.self
        case .SPORTS:
            factoryType = SportsCarFactory.self
        case .SUV:
            factoryType = SUVCarFactory.self
        }
        //取得单例类型
        var factory = factoryType.sharedInstance
        //如果这个类没有实现单例,就init()返回对象即可
        if (factory == nil) {
            factory = factoryType.init()
        }
        return factory
    }
    //子类可以实现这个方法,获取单例
    class var sharedInstance:CarFatory? {
        get{
            return nil
        }
    }
}

然后改动具体工厂Concrete.swift


class CompactCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return StandardFloorplan()
    }
    override func creatSuspension() -> Suspension {
        return RoadSuspension.getInstance()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return FrontWheelDrive()
    }
    //重写父类方法,实现单例
    override class var sharedInstance:CarFatory? {
        get{
            struct SingletonWrapper{
                static let singleton = CompactCarFactory()
            }
            return SingletonWrapper.singleton
        }
    }
}

class SportsCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return ShortFloorplan()
    }
    
    override func creatSuspension() -> Suspension {
        return RaceSuspension.getInstance()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return ALLWheelDrive()
    }
}

class SUVCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return LongFloorplan()
    }
    
    override func creatSuspension() -> Suspension {
        return OffRoadSuspension.getInstance()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return ALLWheelDrive()
    }
}

3.2、结合原型模式:

这里原型模式主要用在具体实现类里,具体实现类里都用到枚举作为返回值。因为Swift的枚举不能实现原型模式的NSCopying协议,所以就需要用到OC的枚举桥接过来使用。这里只对Suspension做改变。

  • 创建OC枚举
屏幕快照 2017-03-31 00.57.15.png
屏幕快照 2017-03-31 00.57.27.png

第一次创建会生成桥接文件,点击Yes就可以,桥接文件的作用,就是引入OC头文件即可让Swift使用。

#import "SuspensionOption.h"

SuspensionOption.h中的枚举是这样写的:

typedef NS_ENUM(NSUInteger, SuspensionOption) {
   SuspensionOptionSTANDARD,
   SuspensionOptionSPORTS,
   SuspensionOptionSOFT
};

然后在修改Suspension.swift

//加入@objc,这样枚举就能实现原型模式
@objc protocol Suspension{
    var suspensionType:SuspensionOption{get}
}

class RoadSuspension: Suspension {
    var suspensionType = SuspensionOption.STANDARD
}

class OffRoadSuspension: Suspension {
    var suspensionType: SuspensionOption = SuspensionOption.SOFT
}

//只对RaceSuspension实现copy功能
class RaceSuspension:NSObject,NSCopying,Suspension{
   
    var suspensionType: SuspensionOption = SuspensionOption.SPORTS
    
    func copy(with zone: NSZone? = nil) -> Any {
        return RaceSuspension()
    }
}

注意:必须在实现类中使用原型模式,而不是在具体工厂中。
原因有两点:
1、除非具体工厂是单例,否则具体工厂使用原型模式会导致出现多个原型对象。

2、哪个实现类为原型,哪个为实例,将散落在工厂类中。

为了避免这两点,Suspension.swift做如下修改:

//加入@objc,这样枚举就能实现原型模式
@objc protocol Suspension{
    var suspensionType:SuspensionOption{get}
    //为了统一copy方法,不让copy方法暴露在工厂方法中
    //添加这个方法统一封装,不让工厂方法知道是否实现copy
    static func getInstance() -> Suspension
}

class RoadSuspension: Suspension {
    var suspensionType = SuspensionOption.STANDARD
    //外界就不能直接创建
    private init(){}
    //只能通过这个方法返回实例
    class func getInstance() -> Suspension{
        return RoadSuspension()
    }
}

class OffRoadSuspension: Suspension {
    var suspensionType: SuspensionOption = SuspensionOption.SOFT
    
    private init(){}
    class func getInstance() -> Suspension{
        return OffRoadSuspension()
    }
}



class RaceSuspension:NSObject,NSCopying,Suspension{
   
    var suspensionType: SuspensionOption = SuspensionOption.SPORTS
    //因为它从NSObject继承了一个空的init
    private override init(){}
    
    func copy(with zone: NSZone? = nil) -> Any {
        return RaceSuspension()
    }
    
    //单例模式
    private class var prototype:RaceSuspension{
    
        get{
            struct SingletonWrapper{
                static let singleton = RaceSuspension()
            }
            return SingletonWrapper.singleton
        }
    }
    //封装copy
    class func getInstance() -> Suspension {
        return prototype.copy() as! Suspension
    }
}

因为Suspension不能通过实例化来生成对象了,只能通过getInstance生成了。修改Concrete.swift

class CompactCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return StandardFloorplan()
    }
    override func creatSuspension() -> Suspension {
        return RoadSuspension.getInstance()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return FrontWheelDrive()
    }
    //重写父类方法,实现单例
    override class var sharedInstance:CarFatory? {
        get{
            struct SingletonWrapper{
                static let singleton = CompactCarFactory()
            }
            return SingletonWrapper.singleton
        }
    }
}

class SportsCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return ShortFloorplan()
    }
    
    override func creatSuspension() -> Suspension {
        return RaceSuspension.getInstance()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return ALLWheelDrive()
    }
}

class SUVCarFactory: CarFatory {
    override func createFloorplan() -> Floorplan {
        return LongFloorplan()
    }
    
    override func creatSuspension() -> Suspension {
        return OffRoadSuspension.getInstance()
    }
    
    override func creatDrivetrain() -> Drivetrain {
        return ALLWheelDrive()
    }
}

小结:

抽象工厂只包含选择具体工厂的逻辑,而具体工厂只包含选择实现类的逻辑,依次串起来。

demo:

SportsStoreDemo中的应用就需要自己去查看了,涉及到StockValueImplementations.swiftStockValueFactories.swiftViewController.swift都在这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容