設(shè)計(jì)模式-創(chuàng)建型
創(chuàng)建型設(shè)計(jì)模式包含:單例模式、原型模式撇叁、工廠方法模式供鸠、抽象工廠模式、建造者模式
單例模式
單例模式在開發(fā)中也是最常見的一種設(shè)計(jì)模式之一陨闹,系統(tǒng)原生提供的很多類的設(shè)計(jì)都采用了單例模式楞捂,例如:
FileManager.default
UserDefaults.standard
NotificationCenter.default
UIApplication.shared
URLSession.shared
其目的是為了節(jié)省內(nèi)存資源并保證數(shù)據(jù)內(nèi)容的一致性,需要讓某些類只能創(chuàng)建一個(gè)實(shí)例趋厉。單例模式有如下特點(diǎn):
- 單例類只有一個(gè)實(shí)例對(duì)象
- 單例類的實(shí)例對(duì)象由自己創(chuàng)建
- 需要對(duì)外提供一個(gè)訪問其實(shí)例對(duì)象的接口
在軟件設(shè)計(jì)中寨闹,有關(guān)全局共享的資源數(shù)據(jù),大型通用的管理類等都可以使用單例模式君账,例如登錄用戶的用戶信息類繁堡、全局的計(jì)時(shí)器、程序的日志管理類
Swift 單例
class ClassA {
static let share = ClassA()
}
Objective-C 單例
static XXClassManager *_defaultManager;
+ (instancetype)shareInstance {
if (!_defaultManager) {
_defaultManager = [[self alloc] init];
}
return _defaultManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (!_defaultManager) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_defaultManager = [super allocWithZone:zone];
});
}
return _defaultManager;
}
- (id)copyWithZone:(NSZone *)zone{
return _defaultManager;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
return _defaultManager;
}
原型模式
以一個(gè)已經(jīng)創(chuàng)建的實(shí)例作為原型乡数,通過復(fù)制該原型對(duì)象來創(chuàng)建出對(duì)象椭蹄,在使用對(duì)象時(shí),使用者無需關(guān)心對(duì)象創(chuàng)建的細(xì)節(jié)净赴。在iOS開發(fā)中:copy
方法就是對(duì)原型設(shè)計(jì)模式的一種實(shí)現(xiàn)绳矩。主要是提供了一種大量創(chuàng)建復(fù)雜對(duì)象的方法。
重構(gòu)前
import Foundation
class Computer {
var cpu: String
var host: String
var screen: String
var uuid: String
init(cpu: String, host: String, screen: String) {
self.cpu = cpu
self.host = host
self.screen = screen
self.uuid = UUID().uuidString
}
func logUUID() {
print(uuid)
}
}
let computer1 = Computer(cpu: "Intel core i7 7700K", host: "GY088-GDF-60", screen: "3008 x 1692")
computer1.logUUID()
此時(shí)若希望創(chuàng)建一臺(tái)相同配置的電腦則只能使用重復(fù)的創(chuàng)建方法
let computer2 = Computer(cpu: "Intel core i7 7700K", host: "GY088-GDF-60", screen: "3008 x 1692")
重構(gòu)后
import Foundation
class Computer {
...
func copy() -> Computer {
return Computer(cpu: self.cpu, host: self.host, screen: self.screen)
}
}
新增一個(gè) copy() 方法玖翅,此時(shí)再創(chuàng)建相同配置的電腦只需調(diào)用原型的 copy() 方法即可翼馆,省去了配件的創(chuàng)建過程。
使用原型模式金度,一旦第一個(gè)對(duì)象被創(chuàng)建应媚,后面的對(duì)象創(chuàng)建都將變得非常容易。其中猜极,作為模板對(duì)象被稱為原型中姜,創(chuàng)建出來的對(duì)象擁有和模板對(duì)象一致的屬性和方法。
工廠方法模式
工廠方法設(shè)計(jì)模式注重于將對(duì)象的創(chuàng)建過程封閉起來跟伏,通過定義抽象的工廠接口和商品接口來隱藏負(fù)責(zé)對(duì)象創(chuàng)建的具體類
對(duì)上述 Computer 類進(jìn)行重構(gòu)
重構(gòu)后
enum Level {
case low
case high
}
protocol ComputerFactoryProtol {
static func getComputer(level: Level) -> ComputerProtol
}
protocol ComputerProtol {
var cpu: String { get }
var host: String { get }
var screen: String { get }
var uuid: String { get }
func logUUID()
}
class Computer: ComputerProtol {
var cpu: String
var host: String
var screen: String
var uuid: String
init(cpu: String, host: String, screen: String) {
self.cpu = cpu
self.host = host
self.screen = screen
self.uuid = UUID().uuidString
}
func logUUID() {
print(uuid)
}
}
class ComputerFactory: ComputerFactoryProtol {
static func getComputer(level: Level) -> ComputerProtol {
switch level {
case .low:
return Computer(cpu: "Intel core i5 3300K", host: "GY088-GDF-10", screen: "1920 x 1080")
case .high:
return Computer(cpu: "Intel core i7 7700K", host: "GY088-GDF-60", screen: "3008 x 1692")
}
}
}
引入的 ComputerFactory 即工廠設(shè)計(jì)模式的具體體現(xiàn)扎筒,外界不再指明具體的配置信息,只需要根據(jù) level 即可創(chuàng)建指定配置的 Computer酬姆,
創(chuàng)建高配電腦嗜桌,例如:
let computer3 = ComputerFactory.getComputer(level: .high)
如果新增加了一種創(chuàng)建方式完全不同的計(jì)算機(jī),我們只需要新建一個(gè)遵守 ComputerProtol
的計(jì)算機(jī)類辞色,之后在 ComputerFactory
中統(tǒng)一處理這種新增的計(jì)算機(jī)類型即可骨宠,對(duì)使用者完全隱藏。
抽象工廠模式
抽象工廠是對(duì)工廠模式的一種升級(jí)相满,核心思路是為各種類型的對(duì)象提供一組統(tǒng)一的創(chuàng)建接口层亿,使用者無需關(guān)心這些對(duì)象具體是如何創(chuàng)建的。
還是上述代碼立美,若我們工廠方法即生產(chǎn) Computer
又可以生產(chǎn) TV
重構(gòu)后
enum Level {
case low
case high
}
protocol ComputerFactoryProtol {
static func getComputer(level: Level) -> ComputerProtol
static func getTV() -> TVProtol
}
protocol TVProtol {
var name: String { get }
func logName()
}
class TV: TVProtol {
var name: String
init(name: String) {
self.name = name
}
func logName() {
print(self.name)
}
}
protocol ComputerProtol {
...
}
class Computer: ComputerProtol {
...
}
class ComputerFactory: ComputerFactoryProtol {
static func getTV() -> TVProtol {
return TV(name: "海爾")
}
static func getComputer(level: Level) -> ComputerProtol {
...
}
}
重構(gòu)后工廠類可以創(chuàng)建不同的對(duì)象匿又,對(duì)于使用者無需關(guān)心創(chuàng)建的細(xì)節(jié),抽象工廠將對(duì)象的創(chuàng)建和使用進(jìn)行了完全分離建蹄。
建造者模式
建造者模式用于復(fù)雜對(duì)象的創(chuàng)建碌更,使代碼聚合性更強(qiáng)裕偿,邏輯更加清晰。建造者模式通常與工程模式配合使用痛单,工廠著重于對(duì)象的創(chuàng)建嘿棘,建造者著重于創(chuàng)建復(fù)雜對(duì)象過程中組成對(duì)象的每一部分創(chuàng)建和最終組裝。
核心在于將復(fù)雜的對(duì)象拆解成多個(gè)簡單對(duì)象旭绒,通過一步步構(gòu)建簡單對(duì)象最終組合成復(fù)雜對(duì)象鸟妙。
重構(gòu)后
enum Foodtype {
case a
case b
}
enum Drink {
case cola
case juice
}
enum Staple {
case hamburger
case chickenRoll
}
class FoodPackage {
var drink: Drink?
var staple: Staple?
}
class BuildA {
var foodPackage = FoodPackage()
func build() -> FoodPackage {
foodPackage.drink = .cola
foodPackage.staple = .hamburger
return foodPackage
}
}
class BuildB {
var foodPackage = FoodPackage()
func build() -> FoodPackage {
foodPackage.drink = .juice
foodPackage.staple = .chickenRoll
return foodPackage
}
}
class FoodFactory {
static func buildFood(type: Foodtype) -> FoodPackage {
switch type {
case .a:
return BuildA().build()
case .b:
return BuildB().build()
}
}
}
let foodPackage = FoodFactory.buildFood(type: .a)
其中,一個(gè)完整的套餐對(duì)象由飲料對(duì)象挥吵、主食對(duì)象組成重父,FoodFactory
為工廠方法,其中根據(jù)套餐類型創(chuàng)建不同的套餐對(duì)象忽匈,具體的套餐對(duì)象的組成則是由 BuildA
和 BuildB
來完成房午。 BuildA
和 BuildB
是建造者模式的核心類,充當(dāng)建造者的角色脉幢。