Help us understand the problem. What is going on with this article?

Swiftでデザインパターン プロトタイプパターン

More than 1 year has passed since last update.

プロトタイプメソッド

  • protocolでcloneメソッドを実装する
  • サブクラスでprotocolを継承し、cloneメソッド内で新しくインスタンスを作成し、returnする
  • 端的にいえば、クラスに自分のコピーを返却するメソッドを実装すること
  • このコピーは別のインスタンスというのが重要(値渡しになる)

メリット

  • クラスは参照渡しになるが、cloneを使えば、値渡しになる
  • クラスからインスタンスを1から作るのが大変な場合、時間などのコストがかかりすぎる場合
  • クラスは通常参照渡しになるが、cloneを使えば、値渡しすることができる
  • 複雑な生成処理を気にしないで良い(例: initに値を渡さなければいけない or 生成の手順などを全く気にしなくて良いので使いやすい
protocol Comment {
    func clone() -> Comment
    func fetchCommentContent() -> [String]
    func pushCommentContent(txt: String)
}

class ArticleComment {
    private var contents = [String]()

    init(contents: [String]) {
        self.contents = contents
    }
}

extension ArticleComment: Comment {
    func clone() -> Comment {
        let vc = ArticleComment(contents: self.contents)
        return vc
    }

    func fetchCommentContent() -> [String] {
        return self.contents
    }

    func pushCommentContent(txt: String) {
        self.contents.append(txt)
    }
}

let comments = ["Amazon最高", "いや、ヨドバシのほうが最高"]
let oldArticleComment = ArticleComment(contents: comments)

// articleCommentを普通に利用する処理があると仮定

// 他の箇所にArticleCommentを渡したい場合
let newArticleComment = oldArticleComment.clone()
newArticleComment.pushCommentContent(txt: "楽天のほうが良い!")

print(oldArticleComment.fetchCommentContent()) // ["Amazon最高", "いや、ヨドバシのほうが最高"]
print(newArticleComment.fetchCommentContent()) // ["Amazon最高", "いや、ヨドバシのほうが最高", "楽天のほうが良い!"]

// 値渡しなので、newArticleCommentに値を追加しても、oldArticleCommentに影響はない
// 複雑な生成処理を気にしないで良い(例: initに値を渡さなければいけない or 生成の手順などを全く気にしなくて良い
// -> インスタンス化が簡単

総評

  • 理解するのは難しくないパターン
  • クラスのインスタンスの使い回しなどで活躍できそう
  • 他の人がいっていたが、画像描画系などで線のコピーはよくある機能なので、そういったところでも活躍できそう
  • チームでやる場合、他の人も読みやすいし、未来の自分も読みやすくなるというメリットもある
  • classは普通に扱うと参照渡しになるが、参照渡しは、複雑になったり障害の元になるなど、危険なため、値渡しになるので安全性は高まると思われた

補足

  • UIViewControllerの場合は、既にcopyメソッドとmutableCopyメソッドが存在する
  • oveerideして使う。overrideしないでcopyメソッドを利用した場合、例外が発生する
import UIKit

class ViewController: UIViewController {

    var txt = ""

    func setup(txt: String) {
        self.txt = txt
    }

    // https://developer.apple.com/documentation/objectivec/nsobject/1418807-copy
    override func copy() -> Any {
        let vc = ViewController()
        vc.setup(txt: self.txt)
        return vc
    }

    // https://developer.apple.com/documentation/objectivec/nsobject/1418978-mutablecopy
    override func mutableCopy() -> Any {
        let vc = ViewController()
        vc.setup(txt: self.txt)
        return vc
    }

    func shout() -> String {
        return self.txt
    }
}

let vc = ViewController()
vc.setup(txt: "test1")

let vc2 = vc.mutableCopy() as! ViewController
//let vc2 = vc.copy() as! ViewController

vc2.setup(txt: "test2")

print(vc.shout())
print(vc2.shout())
bla-bo
Blabo!はちょっとしたひらめきで、商品をつくれるコミュニティです。
https://bla.bo/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away