持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
- 本文主要介绍iOS中最基本的原型模式,原型模式是一种创建型设计模式, 使你能够
复制
已有对象, 而又无需使代码依赖
它们所属的类。
1. 什么是原型模式
原型模式是一种比较简单的设计模式
,客户端知道抽象Prototype
类。在运行时,抽象Prototype
子类的任何对象都可以按照客户端的意愿被赋值,因此,无需手工创建就可以制造同一类型的多个实例。Prototype
声明类复制自身的接口,作为prototype
的子类,ConcretePrototype
实现了Concrete
复制的clone
操作。客户端通过请求原型复制其自身,创造了一个新的对象。
2. 什么时候好使用原型模式
以下情形会考虑使用原型模式
- 需要创建的对象应
独立于
其类型与创建方式。 - 要实例化的类是
运行时
决定的 - 不想要与产品曾是相对应的
工厂层次
- 不同类的实例间的
差异
仅是状态的若干组合
,因此复制相应数量的原型比手工实例化更加方便。 - 类是
不容易创建
,比如每个组件
可以把其他组件作为子节点
的组合对象,线是由点组成的,复制已有的组合对象并对副本进行修改会更加容易。
3. 深拷贝和前拷贝
作为iOS开发我们都知道的概念,深拷贝通常来说相互之间没有影响的,比如在Object-C
中,我们控制器之间进行传值,我们使用copy
,则表示的深拷贝
。2个控制器之间的值将不再影响是相互独立
的。而浅拷贝
则是通过复制指针,它们指向的还是同一片内存空间
。
4. 使用Cocoa Touch框架中的对象复制
Cocoa Touch框架为NSObject
的派生类提供了实现深复制的协议。NSObject
的子类需要实现NSCopying
协议及其方法--(id)copyWithZone:
对于NSObject
有一个实例方法叫做copy
,默认的copy的方法是调用[self copyWithZone:nil]
.对于采纳了NSCopying协议的子类,需要实现这个方法,否则引发异常。
5. 实现复制的方法
import XCTest
class PrototypeRealWorld: XCTestCase {
func testPrototypeRealWorld() {
let author = Author(id: 10, username: "Ivan_83")
let page = Page(title: "My First Page", contents: "Hello world!", author: author)
page.add(comment: Comment(message: "Keep it up!"))
/// Since NSCopying returns Any, the copied object should be unwrapped.
guard let anotherPage = page.copy() as? Page else {
XCTFail("Page was not copied")
return
}
/// Comments should be empty as it is a new page.
XCTAssert(anotherPage.comments.isEmpty)
/// Note that the author is now referencing two objects.
XCTAssert(author.pagesCount == 2)
print("Original title: " + page.title)
print("Copied title: " + anotherPage.title)
print("Count of pages: " + String(author.pagesCount))
}
}
private class Author {
private var id: Int
private var username: String
private var pages = [Page]()
init(id: Int, username: String) {
self.id = id
self.username = username
}
func add(page: Page) {
pages.append(page)
}
var pagesCount: Int {
return pages.count
}
}
private class Page: NSCopying {
private(set) var title: String
private(set) var contents: String
private weak var author: Author?
private(set) var comments = [Comment]()
init(title: String, contents: String, author: Author?) {
self.title = title
self.contents = contents
self.author = author
author?.add(page: self)
}
func add(comment: Comment) {
comments.append(comment)
}
/// MARK: - NSCopying
func copy(with zone: NSZone? = nil) -> Any {
return Page(title: "Copy of '" + title + "'", contents: contents, author: author)
}
}
private struct Comment {
let date = Date()
let message: String
}
打印结果:
Original title: My First Page
Copied title: Copy of 'My First Page'
Count of pages: 2
6. 小结
对于原型模式应该算是最简单的设计模式,通过对对象的深拷贝进行复制一份对象
,类似生物上的细胞的有丝分裂
。适用场景对于一些组合的聚合对象
,比如线和点。线包含点,当我们修改点的时候保存的时候就需要深复制然后归档
。另外就是对于一些对象的只读属性
,我们通过copy
得到新的对象。从而不影响原有的对象。