LoginSignup
2
2

More than 3 years have passed since last update.

[iOS/Swift] アプリ開発の実務的アプローチで学ぶデザインパターン ~Abstract Factory~

Last updated at Posted at 2020-01-13

この記事シリーズは、iOS/Swiftエンジニアである執筆者個人が、
ごく普通のiOSアプリ開発でよくある状況
Swiftのコアライブラリやフレームワークで使われているパターン
着目してデザインパターンを学び直してみた記録です。

関連記事一覧
[iOS/Swift] アプリ開発の実務的アプローチで学ぶデザインパターン

Abstract Factoryパターン概要

  • オブジェクトの生成を抽象化することにより、関連/依存する複数のオブジェクト生成を一括して提供するためのパターンです。
  • Factory Methodと類似していますが、主な相違点は上記の太字部分です。
  • オブジェクト生成の責務を担う側を「抽象的な工場」に見立てて、Abstract Factoryと呼びます。
  • 利用側は「工場」に対して生成条件を提示するわけですが、Swiftの場合はenumを上手く使うと良さそうです。
  • GoFのデザインパターンでは生成に関するパターンに分類されます。

使い所

  • テスト時はDBの処理をモック化するとか
  • (iOSアプリではあまりないと思いますが)マルチデータベース対応 とか

サンプルコード

Swiftバージョンは 5.1 です。

// Protocols
protocol DatabaseConnection {
    var connection: String { get }
}

protocol DatabaseAccessible {
    func select()
    func insert()
    func delete()
    func update()
}

protocol DatabaseProvider {
    func makeConnection() -> DatabaseConnection
    func makeAccessor() -> DatabaseAccessible
}

// Class
final class MockConnection: DatabaseConnection {
    let connection = "MockConnection"
}

final class MockAccessor: DatabaseAccessible {
    func select() { print("ダミーを返す") }
    func insert() { print("何もしない") }
    func delete() { print("何もしない") }
    func update() { print("何もしない") }
}

final class ProductionConnection: DatabaseConnection {
    let connection = "ProductionConnection"
}

final class ProductionAccessor: DatabaseAccessible {
    func select() { print("実際に読み込む") }
    func insert() { print("実際に追加する") }
    func delete() { print("実際に削除する") }
    func update() { print("実際に更新する") }
}

// Abstract factory
enum DatabaseFactoryType: DatabaseProvider {
    case mock
    case production

    func makeConnection() -> DatabaseConnection {
        switch self {
        case .mock:
            return MockConnection()
        case .production:
            return ProductionConnection()
        }
    }

    func makeAccessor() -> DatabaseAccessible {
        switch self {
        case .mock:
            return MockAccessor()
        case .production:
            return ProductionAccessor()
        }
    }
}

// Usage
let mockFactory = DatabaseFactoryType.mock
let mockConnection = mockFactory.makeConnection()
print(mockConnection.connection)   // "MockConnection"
let mockAccessor = mockFactory.makeAccessor()
mockAccessor.select()  // "ダミーを返す"

let productionFactory = DatabaseFactoryType.production
let productionConnection = productionFactory.makeConnection()
print(productionConnection.connection)   // "ProductionConnection"
let productionAccessor = productionFactory.makeAccessor()
productionAccessor.select()  // "実際に読み込む"
2
2
0

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
2
2