iOS设计模式之原型模式

持续创作,加速成长!这是我参与「掘金日新计划 · 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得到新的对象。从而不影响原有的对象。

作者:潜水的鱼儿 原文地址:https://juejin.cn/post/7101677211769389069

%s 个评论

要回复文章请先登录注册