创建型模式-抽象工厂

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

意义:

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

原理描述:

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

具体使用:

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、该怎么干:

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

创建型模式-抽象工厂_第1张图片
屏幕快照 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枚举
创建型模式-抽象工厂_第2张图片
屏幕快照 2017-03-31 00.57.15.png
创建型模式-抽象工厂_第3张图片
屏幕快照 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都在这里

你可能感兴趣的:(创建型模式-抽象工厂)