美文网首页
创建型模式-抽象工厂

创建型模式-抽象工厂

作者: 关灯侠 | 来源:发表于2017-04-01 01:37 被阅读7次

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

    意义:

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

    原理描述:

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

    具体使用:

    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都在这里

    相关文章

      网友评论

          本文标题:创建型模式-抽象工厂

          本文链接:https://www.haomeiwen.com/subject/sfhmottx.html