CompositeパターンをSwiftで書いてみる


はじめに

本記事ではGoFのデザインパターンの一種であるCompositeパターンをSwiftで書いてみる内容となっています.

Compositeパターンとは

Compositeは日本語で「複合物」などの意味がある.
Compositeパターンのコンセプトは「容器と中身を同一視」して再帰的な処理を容易にすること.

わかりやすい例としてよく挙げられるのがファイルシステム
フォルダを削除するときにその配下にあるものファイルやフォルダを同一視して削除できたほうが都合がいい.

クラス図

ファイルシステムを例として作成したクラス図です. 
ディレクトリとファイルのクラスに加えてそれぞれに共通する削除メソッドを持ったEntryというインターフェースを定義しています.

Swiftで書いてみる

Entry

protocol Entry {
    func remove()
}

Entryはprotocolで定義します.

File

struct File: Entry {
    private var name: String

    init(name: String) {
        self.name = name
    }

    func remove() {
        print("\(self.name)を削除しました.")
    }
}

Fileクラス Entryプロトコルに準拠しています.

Directory

struct Directory: Entry {
    private var name: String
    private var directories: [Entry] = []

    init(name: String) {
        self.name = name
    }

    mutating func add(entry: Entry) {
        self.directories.append(entry)
    }

    func remove() {
        for dir in self.directories {
            dir.remove()
        }
        print("\(self.name)を削除しました.")
    }
}

Directoryクラス こちらも同様にEntryプロトコルに準拠しています.

メイン

// ファイルを作成
let file1 = File(name: "file1")
let file2 = File(name: "file2")
let file3 = File(name: "file3")
let file4 = File(name: "file4")

// フォルダ1を作成
var dir1 = Directory(name: "dir1")
// ファイル1と2をフォルダ1に入れる
dir1.add(entry: file1)
dir1.add(entry: file2)

var dir2 = Directory(name: "dir2")
dir2.add(entry: dir1)
dir2.add(entry: file3)
dir2.add(entry: file4)

dir2.remove()

実行結果

file1を削除しました.
file2を削除しました.
dir1を削除しました.
file3を削除しました.
file4を削除しました.
dir2を削除しました.

まとめ

このパターンのメリットとしてはオブジェクトが共通のインターフェースを持っていることで実行側で中身を意識することなく使えるところだと思います.
また,新たにオブジェクトを追加する必要が出た場合も容易に実装できそうですね.

以下,活用例としてCompositeパターンを使ったValidationを実装した記事を見つけたので載せておきます.
【iOS】アプリクライアント側での文字入力のValidation機構について(UITextField, UITextViewなど)

もっと色んなデザインパターンを学んで活用していきたいですね〜

参考

TECHSCORE Compositeパターン
デザインパターン ~Composite~