🙂

デフォルト動作のためにデフォルト引数を利用する

2022/01/03に公開約1,400字

まえがき

この文章は書籍Effective Swiftのための下書きの一部「デフォルト動作のためにデフォルト引数を利用する」の項目をアルファ版として公開してみます。
なお、下書きのためこちらのタイミングで非公開にすることはあります。

その他、もしかしたら私の勘違いがあったりするかもしれません。できればコメントください。

気になっているのは、あっさり書きすぎているかもしれないのでもう少し例を複雑にした方がメリットがわかるかもしれないってことです。公開して見返しつつ修正していくかもしれません。

デフォルト動作のためにデフォルト引数を利用する

関数の引数にデフォルト値を指定することによって、関数呼び出し側が引数を与えなければその指定したデフォルト値を利用することができます。どのような関数でもデフォルト値は指定できるため、型のinitにも利用できます。

デフォルト動作ではデータベースとしてデフォルト引数のCore Dataが利用される例を示します。

class DBClient {
    private let coreDataStack: CoreDataStack
    
    init(coreDataStack: CoreDataStack = CoreDataStack()) {
        self.coreDataStack = coreDataStack
    }
}

// デフォルト動作を期待する利用側では引数のことを考えなくて済む
let dbClient = DBClient()

例のように、DBClientの呼び出し側は引数coreDataStackの指定を省略してインスタンス化して利用できることで、その詳細を知る必要はありません。

このDBClientを使った機能をテストする際に、実際の永続化されたデータを利用するのではなく、永続化されていないメモリ上のデータを利用することが必要になった場合を考えてみます[1]

テストのためにメモリ上のCore Dataを利用できるようにするextensionを追加し、呼び出し側はinitの引数を与えるようにします。

// Core Dataを使ったテストコード

extension CoreDataStack {
    /// メモリ上で読み書きするだけのCore Dataを用意する
    static func memoryStore() {
        ...
    }
}

let dbClient = DBClient(coreDataStack: .memoryStore())

通常利用時には引数を省略でき、どのような初期化がふさわしいのか考えずコードを書けるメリットがあり、テスト時には必要に応じてメモリを使うことを明示するだけです[2]

脚注
  1. メモリ上のデータはテストコードの実行が終了するとすべてクリアされるため、テストをクリーンに実行し、さらにその結果を持ち越さない利点があります。 ↩︎

  2. テストターゲット内でテスト用のmemoryStore()関数を定義することで、通常利用時には利用できないようにし、テストコードを編集する場合にのみXcodeのコード補完候補に出るようにすることも重要です。 ↩︎

Discussion

ログインするとコメントできます