使用場景:繼承,創(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
必須由三部分組成:Floorplan
峦耘、Suspension
、Drivetrain
旅薄。而這三部分都有各自的子類辅髓,通過不同的子類組合就有了carType
。那么抽象工廠解決的就是誰去創(chuàng)建這三部分子類少梁、誰去組裝子類洛口。
2、該怎么干:
大體分兩個步驟凯沪,一個抽象工廠類第焰、一個具體工廠類。抽象工廠類提供創(chuàng)建子類的方法妨马,由具體工廠類繼承實現(xiàn)挺举;抽象工廠還有一個對外提供選擇的接口,根據(jù)外界條件生成具體工廠類身笤。
以下為選讀
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
枚舉
第一次創(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.swift
楞慈、StockValueFactories.swift
、ViewController.swift
都在這里