LoginSignup
8

More than 5 years have passed since last update.

[Swift] Builderパターンを例にPhantom Typeでメソッドの事前実行を強制する

Posted at

あるメソッドの実行の前にそれ以外のメソッドを必ず実行したい場合にPhantom Typeを利用して実装することができます。例えばBuilderパターンでビルドを行う前に必ず値を設定するメソッドを実行しておきたいといった時です。

以下のコードではageとjobを設定しなければbuildメソッドが呼べません。

class BuilderState {}
class Buildable: BuilderState {}
class Unbuildable: BuilderState {}

class UserBuilder<Age: BuilderState, Job: BuilderState> {
    fileprivate let age: UInt
    fileprivate let job: String

    fileprivate init(age: UInt, job: String) {
        self.age = age
        self.job = job
    }

    static var builder: UserBuilder<Unbuildable, Unbuildable> {
        return UserBuilder<Unbuildable, Unbuildable>(age: 0, job: "")
    }

    func set(age: UInt) -> UserBuilder<Buildable, Job> {
        return UserBuilder<Buildable, Job>(age: age, job: job)
    }

    func set(job: String) -> UserBuilder<Age, Buildable> {
        return UserBuilder<Age, Buildable>(age: age , job: job)
    }
}

extension UserBuilder where Age: Buildable, Job: Buildable {
    func build() -> User {
        return User(age: age, job: job)
    }
}

struct User {
    let age: UInt
    let job: String
}

let user = UserBuilder.builder.set(age: 39).set(job: "Programmer").build()

BuildStateクラスを基底とするBuildable・UnbuildableクラスはBuilderの状態を表します。Userを作成するためのUserBuilderはAgeとJobという状態を持っています。UserBuilder.builder()でインスタンスを取得するとそのインスタンスはAge・JobともUnbuildableなのでbuildメソッドは実行できません。set(age:)を実行するとAgeはBuildableになります。しかしJobは依然Unbuildableなのでまだbuild()メソッドを実行することはできません。さらにset(job:)メソッドを実行するとAge・JobともBuildableになりbuild()メソッドを実行することができるようになります。

以上のように、Phantom Typeを使うとメソッドの事前実行を強制することが可能です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8