創(chuàng)建型模式-抽象工廠

使用場景:繼承,創(chuàng)建各種子類對象,多種繼承關系

意義:

隱藏了選擇子類、創(chuàng)建子類對象的過程,隱藏各對象間的相互關系,簡化對外接口

原理描述:

可以看作是多個工廠方法生產(chǎn)出各種類型對象后,這些毫無關系的對象,由抽象工廠方法聯(lián)系起來。

具體使用:

1、平常使用的方式

創(chuàng)建一個名為AbstractFactory的OS X命令行工具項目。如上面說的,多種繼承關系,下面就創(chuàng)建各種不同的協(xié)議、和繼承協(xié)議的子類。首先創(chuàng)建第一個協(xié)議及子類Floorplans.swift

//協(xié)議
protocol Floorplan {
    var seats:Int{get}
    var enginePosition:EngineOption {get}
}

enum EngineOption:String {
    case FRONT = "Front";
    case MID = "Mid";
}
//協(xié)議繼承的子類
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
}

第二個協(xié)議及子類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
}

再創(chuàng)建第三個協(xié)議及子類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
}

為了讓三個協(xié)議之間有聯(lián)系,創(chuàng)建CarsParts.swift

enum Cars:String {
    case COMPACT = "VM Golf";
    case SPORTS = "Porsche Boxter";
    case SUV = "Cadillac Escalade";
}
//由三種協(xié)議子類對象、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()
問題:創(chuàng)建結構體對象car時,用到了每個協(xié)議的具體實現(xiàn)方法,這樣暴露出去的壞處在于,實現(xiàn)方法改變后,car的初始化方法也會改變。我們想,可不可以提供一個隱藏所有選擇細節(jié)的方法?類似于這樣var car = Car(carType:Cars.SPORTS)
2、實現(xiàn)抽象工廠
  • 創(chuàng)建抽象工廠類:
    創(chuàng)建Abstract.swift
    提供創(chuàng)建每個類型的方法,沒有實現(xiàn),由子類重寫實現(xiàn)
class CarFatory{

    func createFloorplan() -> Floorplan {
        fatalError("Not implemented")
    }
    
    func creatSuspension() -> Suspension {
        fatalError("Not implemented")
    }
    
    func creatDrivetrain() -> Drivetrain {
        fatalError("Not implemented")
     }
  }
  • 具體工廠類
    創(chuàng)建Concrete.swift
    繼承抽象工廠,重寫創(chuàng)建方法,實現(xiàn)每個類型具體創(chuàng)建
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()
    }
}

抽象工廠類應該是漏了一個選擇的邏輯,根據(jù)類型選擇合適的工廠方法。于是在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現(xiàn)在使用起來是這樣的:

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()
}

現(xiàn)在雖然沒有暴露選擇細節(jié),但是調用組件的細節(jié)暴露出來,干脆把調用組件也隱藏起來。

于是在CarParts.swift中添加init方法把調用組件的細節(jié)加進去。

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
   //把調用組件的細節(jié)放在初始化過程 
    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)")
    }
}

至此抽象工廠已經(jīng)完整實現(xiàn),我們捋一捋思路:

1、在干什么:

創(chuàng)建一個車car,car必須由三部分組成:FloorplanSuspensionDrivetrain。而這三部分都有各自的子類,通過不同的子類組合就有了carType。那么抽象工廠解決的就是誰去創(chuàng)建這三部分子類、誰去組裝子類。

2、該怎么干:

大體分兩個步驟,一個抽象工廠類、一個具體工廠類。抽象工廠類提供創(chuàng)建子類的方法,由具體工廠類繼承實現(xiàn);抽象工廠還有一個對外提供選擇的接口,根據(jù)外界條件生成具體工廠類。

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

以下為選讀

3、抽象工廠和其他模式結合的場景:
3.1、結合單例模式:

首先改動一下抽象工廠Abstract.swift

class CarFatory{
    
    //避免下面創(chuàng)建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
        //如果這個類沒有實現(xiàn)單例,就init()返回對象即可
        if (factory == nil) {
            factory = factoryType.init()
        }
        return factory
    }
    //子類可以實現(xiàn)這個方法,獲取單例
    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()
    }
    //重寫父類方法,實現(xiàn)單例
    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、結合原型模式:

這里原型模式主要用在具體實現(xiàn)類里,具體實現(xiàn)類里都用到枚舉作為返回值。因為Swift的枚舉不能實現(xiàn)原型模式的NSCopying協(xié)議,所以就需要用到OC的枚舉橋接過來使用。這里只對Suspension做改變。

  • 創(chuàng)建OC枚舉
屏幕快照 2017-03-31 00.57.15.png
屏幕快照 2017-03-31 00.57.27.png

第一次創(chuàng)建會生成橋接文件,點擊Yes就可以,橋接文件的作用,就是引入OC頭文件即可讓Swift使用。

#import "SuspensionOption.h"

SuspensionOption.h中的枚舉是這樣寫的:

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

然后在修改Suspension.swift

//加入@objc,這樣枚舉就能實現(xiàn)原型模式
@objc protocol Suspension{
    var suspensionType:SuspensionOption{get}
}

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

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

//只對RaceSuspension實現(xiàn)copy功能
class RaceSuspension:NSObject,NSCopying,Suspension{
   
    var suspensionType: SuspensionOption = SuspensionOption.SPORTS
    
    func copy(with zone: NSZone? = nil) -> Any {
        return RaceSuspension()
    }
}

注意:必須在實現(xiàn)類中使用原型模式,而不是在具體工廠中。
原因有兩點:
1、除非具體工廠是單例,否則具體工廠使用原型模式會導致出現(xiàn)多個原型對象。

2、哪個實現(xiàn)類為原型,哪個為實例,將散落在工廠類中。

為了避免這兩點,Suspension.swift做如下修改:

//加入@objc,這樣枚舉就能實現(xiàn)原型模式
@objc protocol Suspension{
    var suspensionType:SuspensionOption{get}
    //為了統(tǒng)一copy方法,不讓copy方法暴露在工廠方法中
    //添加這個方法統(tǒng)一封裝,不讓工廠方法知道是否實現(xiàn)copy
    static func getInstance() -> Suspension
}

class RoadSuspension: Suspension {
    var suspensionType = SuspensionOption.STANDARD
    //外界就不能直接創(chuàng)建
    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()
    }
    //重寫父類方法,實現(xiàn)單例
    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()
    }
}

小結:

抽象工廠只包含選擇具體工廠的邏輯,而具體工廠只包含選擇實現(xiàn)類的邏輯,依次串起來。

demo:

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容