设计模式-创建型模式

设计模式-创建型模式

对象模版模式

对象模版模式是最简单的一种设计模式,即使用类和结构体创建对象,而不是使用零散的变量、变量数组或元组来保存信息。使用对象模版模式可以将数据与操作数据的方法封装在一起,从而隐藏接口的内部实现,松散耦合。

原型模式

原型模式是指用已有的对象作为原型,通过克隆的方式来创建新的对象,而不是通过初始化函数。这样可以将创建对象的代码隐藏,无需知道创建新的对象需要用到哪些类或结构体。当初始化的开销很大,或是想要降低对模版的依赖时,就可以使用此模式。

当使用值类型时,Swift 会自动使用原型模式。而当我们使用引用类型时,就需要让类继承 NSObject 并遵循 NSCopying 协议,实现其中的 copyWithZone 方法来定义如何复制对象。需要注意在复制对象时使用深拷贝还是浅拷贝。

单例模式

单例模式可以确保某个类型的对象在应用程序中只出现一个实例。单例模式的实现与所使用的语言密切相关。

在 Swift 中,可以使用全局常量来实现单例模式:

1
2
3
4
5
6
7
8
//Logger.swift
let globalLogger = Logger()
final class Logger {
fileprivate init() {
//required to stop instances being created by code in other files.
}
//...
}

Swift 的全局常量是惰性初始化的,且能保证线程安全。只有在第一次访问全局常量时才会初始化,且只初始化一次。即使在另外的线程中读取,也只会创建一个实例。

我们使用 final 关键字来修饰类,来防止子类的创建。把 init 函数前面加上 fileprivate 来阻止 Logger.swift 以外的地方的代码来创建实例。通过 let 关键字来声明对象,可以防止引用的指向被修改。这样就实现了一个单例。

当然还有更简单的实现方法:

1
2
3
4
final class Logger {
static let sharedLogger = Logger()
private init() {}
}

Cocoa 中许多地方都使用了单例模式,比如 UIApplication 的 sharedApplication。

对象池模式

对象池模式是单例模式的一种变体,不同的是它提供了多个完全相同的对象,而非单个对象。使用时应该从对象池中取出对象,使用它完成任务后再归还给对象池。在归还以前,其他组件将不能使用它。

举例来说明,图书馆中绝大多数书都不止一本,但是范围又是有限定的。创建或复制 Book 对象并不能使图书馆的藏书量真的增多,这个时候就应该使用对象池来管理图书。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Pool<T> {
private var data = [T]()

init(items: [T]) {
for eachItem in items {
data.append(eachItem)
}
}

func getFromPool() -> T? {
var result: T?
if data.count > 0 {
result = data.removeAtIndex(0)
}
return result
}

func returnToPool(item: T) {
data.append(item)
}
}

我们维护了一个队列来管理对象池。需要注意的是,如果程序中使用了多线程,则需要做好数据的保护。

Cocoa 中,UITableView 维护了一个 UITableViewCell 的对象池来节省内存开销。

工厂方法模式

当多个类遵循同一个协议,或是继承自同一个基类,而我们需要根据条件选择一个类来初始化对象时,就可以使用工厂方法模式。工厂方法模式同意了实现类的选取逻辑,从而避免了相关逻辑散布在整个程序中,调用组件无需了解实现类即选取实现类的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//RentalCar.swift
class RentalCar {
fileprivate var name = ""
fileprivate var passengers = 0

fileprivate init(name: String, passengers: Int) {
self.name = name
self.passengers = passengers
}

final var name: String {
get { return name }
}

final var passengers: Int {
get { return passengers }
}

class func createRentalCar(passengers: Int) -> RentalCar? {
var car: RentalCar?
switch passengers {
case 0...3:
car = Compact()
case 4...8:
car = SUV()
default:
car = nil
}
return car
}
}

class Compact: RentalCar {
fileprivate init() {
super.init(name: "Golf", passengers: 3)
}
}

class SUV: RentalCar {
fileprivate init() {
super.init(name: "Range Rover", passengers: 8)
}
}

//CarSelector.swift
class CarSelector {
class func selectCar(passengers: Int) -> String? {
return RentalCar.createRentalCar(passengers)?.name
}
}

抽象工厂模式

当调用组件需要一组互相协作的对象,又不需要关心这些对象的具体协作方式时,就可以使用抽象工厂模式。

当调用抽象工厂去创建对象时,抽象工厂会检查请求,然后选择一个具体工厂,使用具体工厂创建对象并返回给调用组件。

建造者模式

建造者模式用于分离对象的创建和配置。调用组件负责提供配置对象的数据,把数据传给中间人建造者,建造者再去创建对象。这样调用者就无需过多掌握其使用的对象的信息,而默认配置可以集中放置在建造者中。如果创建对象需要进行复杂的配置,就可以使用这种模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Burger {
let pickles: Bool //泡菜
let mayo: Bool //蛋黄酱
let lettuce: Bool //生菜
let ketchup: Bool

init(pickles: Bool, mayo: Bool, lettuce: Bool, ketchup: Bool) {
self.pickles = pickles
self.mayo = mayo
self.lettuce = lettuce
self.ketchup = ketchup
}
}

class BurgerBuilder {
private var pickles = false
private var mayo = false
private var lettuce = true
private var ketchup = true

func setPickles(choice: Bool) {
self.pickles = choice
}

func setMayo(choice: Bool) {
self.mayo = choice
}

func setLettuce(choice: Bool) {
self.lettuce = choice
}

func setKetchup(choice: Bool) {
self.ketchup = choice
}

func buildBurger() -> Burger {
return Burget(pickles: picklse, mayo: mayo, lettuce: lettuce, ketchup: ketchup)
}
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×