使用场景:继承,创建各种子类对象,多种继承关系
意义:
隐藏了选择子类、创建子类对象的过程,隐藏各对象间的相互关系,简化对外接口
原理描述:
可以看作是多个工厂方法生产出各种类型对象后,这些毫无关系的对象,由抽象工厂方法联系起来。
具体使用:
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
必须由三部分组成:Floorplan
、Suspension
、Drivetrain
。而这三部分都有各自的子类,通过不同的子类组合就有了carType
。那么抽象工厂解决的就是谁去创建这三部分子类、谁去组装子类。
2、该怎么干:
大体分两个步骤,一个抽象工厂类、一个具体工厂类。抽象工厂类提供创建子类的方法,由具体工厂类继承实现;抽象工厂还有一个对外提供选择的接口,根据外界条件生成具体工厂类。
以下为选读
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
枚举
第一次创建会生成桥接文件,点击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.swift
、StockValueFactories.swift
、ViewController.swift
都在这里