创建型模式-工厂方法
使用场景:继承,创建各种子类对象,一种继承关系意义: 隐藏了选择子类、创建子类对象的过程,统一创建接口
原理描述: 这里强调一个管理类(通常用基类)、一个方法、返回不同子类对象。
当然如果有复杂的层级,只需要重复这个过程。
![创建型模式-工厂方法](http://img.readke.com/220906/1513256347-0.jpg)
文章图片
工厂模式原理图.png 具体使用: 1、一个常用、错误示范。 创建一个
FactoryMethod
的OS X
命令行工程,创建一个RentalCar.swift
文件//协议
protocol RentalCar{
var name:String{get}
var passengers:Int{get}
var pricePerDay:Float{get}
}//协议继承
class Compact: RentalCar {
var name = "VM Golf"
var passengers = 3
var pricePerDay: Float = 20
}class Sports:RentalCar{var name = "Porsche Boxter"
var passengers: Int = 1
var pricePerDay: Float = 100
}class SUV: RentalCar {
var name = "Cadillac Escalade"
var passengers: Int = 8
var pricePerDay: Float = 75
}
再创建一个
CarSelector.swift
,一个调用类class CarSelector{class func selectCar(passengers:Int) -> String?{
var car:RentalCar?
switch passengers {
case 0...1:
car = Sports()
case 2...3:
car = Compact()
case 4...8:
car = SUV()
default:
car = nil
}
return car?.name
}
}
最后在
main.swift
中使用let passengers = [1,3,5]for p in passengers{print("\(p) pasengers:\(CarSelector.selectCar(passengers: p)!)")
}
使用的时候好像没有什么问题,新增一个类型的时候,看看需要改变哪些地方。
在
RentalCar.swift
新增一个类型Minivan
...
class SUV: RentalCar {
var name = "Cadillac Escalade"
var passengers: Int = 8
var pricePerDay: Float = 75
}
//新增类型
class Mininvan: RentalCar{var name = "Chevrolet Evpress"
var passengers = 14
var pricePerDay: Float = 40
}
新增类型后,
CarSelector.swift
也需要更改:class CarSelector{class func selectCar(passengers:Int) -> String?{
var car:RentalCar?
switch passengers {
case 0...1:
car = Sports()
case 2...3:
car = Compact()
case 4...8:
car = SUV()
//新增逻辑
case 9...14:
car = Mininvan()
default:
car = nil
}
return car?.name
}
}
1.1、问题:CarSelector需要知道所有子类类型,一旦新增子类,就需要更新逻辑。 新增一个调用类
PriceCalculator.swift
,还会有哪些问题?class PriceCalculator{class func calculatorPrice(passengers:Int,days:Int) -> Float?{
var car:RentalCar?
switch passengers {
case 0...1:
car = Sports()
case 2...3:
car = Compact()
case 4...8:
car = SUV()
//新增逻辑
case 9...14:
car = Mininvan()
default:
car = nil
}
return car == nil ? nil : car!. pricePerDay* Float(days)
}
}
1.2、问题:新增调用类,会重写一遍选择逻辑。思考一下,这段选择逻辑是可以隐藏起来的,调用类根本不需要关心这些,它只需要一个子类对象就可以了。 2、解决办法:封装选择逻辑,提供调用类一个获取对象的方法即可。 2.1、全局方法: 在
RentalCar.swift
中创建一个全局方法封装选择逻辑:func creatRentalCar(passengers:Int) -> RentalCar?{var car:RentalCar?switch passengers {
case 0...1:
car = Sports()
case 2...3:
car = Compact()
case 4...8:
car = SUV()
case 9...14:
car = Mininvan()
default:
car = nil
}
return car
}protocol RentalCar{var name:String{get}
var passengers:Int{get}
var pricePerDay:Float{get}
}
...
CarSelector.swift
使用起来就是这样的class func selectCar(passengers:Int) -> String?{return creatRentalCar(passengers: passengers)?.name
}
PriceCalculator.swift
class func calculatePrice(passengers:Int,days:Int) -> Float?{letcar = creatRentalCar(passengers: passengers)
return car == nil ? nil : car!.pricePerDay * Float(days)
}
选择逻辑完全隐藏起来,新增类、删除类,调用类根本不用变动。
2.2、使用基类 改造
RentalCar.swift
,使用基类替换协议,适当减少子类,为后续改变做准备。class RentalCar{
private var nameBV :String
private var passengersBV:Int
private var pricePerDayBV:Floatprivate init(name:String,passengers:Int,price:Float) {
self.nameBV = name
self.passengersBV = passengers
self.pricePerDayBV = price
}final var name:String{
get{ return nameBV }
}final var passengers:Int{
get { return passengersBV}
}final var pricePerDay:Float{
get { return pricePerDayBV }
}
class func creatRentalCar(passengers:Int) -> RentalCar?{var carI:RentalCar?switch passengers {
case 0...3:
car = Compact()
case 4...8:
car = SUV()
default:
car = nil
}
return car
}
class Compact:RentalCar{fileprivate init(){
self.init(name: "VM Golf", passengers: 3, price: 20)
}
}class SUV:RentalCar{fileprivate init(){
super.init(name: "Cadillac Escalade", passengers: 8, price: 75)
}
}
}
使用基类时,为了达到协议的效果,使用
final
关键字修饰属性,避免属性被修改。还定义了一个私有构造方法,需要传递参数。CarSelector.swift
使用是这样的:class func selectCar(passengers:Int) -> String?{return RentalCar.creatRentalCar(passengers: passengers)?.name
}
PriceCalculator.swift
: class func calculatePrice(passengers:Int,days:Int) -> Float?{letcar = RentalCar.creatRentalCar(passengers: passengers)
return car == nil ? nil : car!.pricePerDay * Float(days)
}
以下可选,对理解工厂模式影响不大,只是应用得更复杂,如果只是简单运用,到这里就可以了。 如果你能看懂我画的原理图,那么似乎还有一种稍微复杂的场景,子类里面还有子类实现。
3、子类里还有子类,可以把选择逻辑放到更深,如原理图。
RentalCar.swift
新增一个继承Compact
的子类SmallCompact
class RentalCar{
private var nameBV :String
private var passengersBV:Int
private var pricePerDayBV:Floatprivate init(name:String,passengers:Int,price:Float) {
self.nameBV = name
self.passengersBV = passengers
self.pricePerDayBV = price
}final var name:String{
get{ return nameBV }
}final var passengers:Int{
get { return passengersBV}
}final var pricePerDay:Float{
get { return pricePerDayBV }
}
class func creatRentalCar(passengers:Int) -> RentalCar?{//元类型,RentalCar的任意类型,包括本身类型、还有子类类型
var carImpl:RentalCar.Type?switch passengers {
case 0...3:
carImpl = Compact.self
case 4...8:
carImpl = SUV.self
default:
carImpl = nil
}
return carImpl?.creatRentalCar(passengers: passengers)
}class Compact:RentalCar{fileprivate convenience init(){
self.init(name: "VM Golf", passengers: 3, price: 20)
}fileprivate override init(name:String,passengers:Int,price:Float){
super.init(name: name, passengers: passengers, price: price)
}
//override重写父类方法,子类的选择逻辑
override class func creatRentalCar(passengers:Int) -> RentalCar?{
if passengers < 2 {
return Compact()
}else{
return SmallCompact()
}
}class SmallCompact: Compact {
fileprivate init(){
super.init(name: "Ford Fiesta", passengers: 3, price: 15)
}
}class SUV:RentalCar{fileprivate init(){
super.init(name: "Cadillac Escalade", passengers: 8, price: 75)
}override class func creatRentalCar(passengers:Int) -> RentalCar?{
return SUV()
}
}
}
- 里面使用到
.Type
,个人理解就是RentalCar
的任意类型,包括本身类型、还有子类类型。.self
就是具体的类型,这里就是指每个子类。如果你要了解详情,可以看看这个、还有王巍 (@ONEVCAT)的TIP。
class RentalCar{
private var nameBV :String
private var passengersBV:Int
private var pricePerDayBV:Floatprivate init(name:String,passengers:Int,price:Float) {
self.nameBV = name
self.passengersBV = passengers
self.pricePerDayBV = price
}final var name:String{
get{ return nameBV }
}final var passengers:Int{
get { return passengersBV}
}final var pricePerDay:Float{
get { return pricePerDayBV }
}
class func creatRentalCar(passengers:Int) -> RentalCar?{//元类型,RentalCar的任意类型,包括本身类型、还有子类类型
var carImpl:RentalCar.Type?switch passengers {
case 0...3:
carImpl = Compact.self
case 4...8:
carImpl = SUV.self
default:
carImpl = nil
}
return carImpl?.creatRentalCar(passengers: passengers)
}class Compact:RentalCar{fileprivate convenience init(){
self.init(name: "VM Golf", passengers: 3, price: 20)
}fileprivate override init(name:String,passengers:Int,price:Float){
super.init(name: name, passengers: passengers, price: price)
}
//override重写父类方法
override class func creatRentalCar(passengers:Int) -> RentalCar?{
if passengers < 2 {
return shareInstance
}else{
return SmallCompact.shareInstance
}
}//单例
class var shareInstance:RentalCar{get{
struct SingletonWrapper{
static let singleton = Compact()
}
return SingletonWrapper.singleton
}
}
}class SmallCompact: Compact {
fileprivate init(){
super.init(name: "Ford Fiesta", passengers: 3, price: 15)
}override class var shareInstance:Compact{
get{
struct SingletonWrapper{
static let singleton = SmallCompact()
}
return SingletonWrapper.singleton
}}
}class SUV:RentalCar{fileprivate init(){
super.init(name: "Cadillac Escalade", passengers: 8, price: 75)
}override class func creatRentalCar(passengers:Int) -> RentalCar?{
return SUV()
}
}
}
总结: 提供一个方法,封装好选择子类对象的逻辑,避免暴露细节。
-
Demo
在这里,05工厂模式
、SportsStoreDemo
里面涉及的类Product.swift
、ProductDataStore
《精通Swift设计模式》
,如果有兴趣可以直接买来看看,不用看我的"歪曲理解"。我只是一个搬运工,记录过程,记录一点浅显的理解。推荐阅读
- PPP模式中政府部门的支持措施
- 外观模式-Facade
- Go设计模式-单例模式
- 设计模式之(9)——适配器|设计模式之(9)——适配器 模式
- 连载2|连载2|吃货变投资人进阶(商业模式决定了投资价值(中))
- 1/30|1/30 打破固有的思维模式,创造出独特的主意
- 投稿|最高分账4400万+,云影院模式有多赚钱?
- 【译】Go语言编程模式
- 解决gitlab|解决gitlab runner在docker模式下报 503 Service Unavailable 错误
- 【设计模式】Java设计模式|【设计模式】Java设计模式 -工厂模式