Abstract Factory

デザインパターンとは

デザインパターンとはオブジェクト思考開発における先人たちが作り上げてきた便利な設計図です。

Gang of Four通称Gofが1994年に出版した『オブジェクト指向における再利用のためのデザインパターン』の中で23個の設計図が紹介されています。

Note

デザインパターンのサンプルコードはSwift4でまとめます。

アブストラクトファクトリーパターンとは?

Abstract factoryを直役すると、読んで字の如し「抽象的な工場」です。

インスタンスを生成するクラスを用意して生成処理の部分を分割することで、開発者はなんのオブジェクトを生成しているかを知らなくても、開発を進めることができます。

サンプルコード

サンプルコードではラーメンについて考えてみます、味噌ラーメン、塩ラーメン、醤油ラーメン、豚骨ラーメン、二郎系ラーメンなどいろいろありますが、以下のものからできています。

スープ

チャーシュー

その他トッピング

ラーメンのプロトコル

ラーメンの概念が決まったのでラーメンのprotocolを作成します。

protocol Ramen {
    func createSoup() -> String
    func createNoodle() -> String
    func createGrilledPork() -> String
    func createOtherTopping() -> Any
}

ラーメンの種類

enum RamenType {
    case Miso
    case Shoyu
    case Sio
    case Tonkotu
    case Jiro
}

Factoryクラス

このサンプル例でのRamenFactoryは注文を聞いてくれる看板娘のような立ち位置で、お客さんから受けた注文を受けたら各ラーメンの職人さんにラーメンを作ってもらいます。

看板娘がラーメンの作り方は知っていますが、実際に作ることはできず呼び出すとエラーになります。

class RamenFactory:Ramen {
    
    func createRamen(type: RamenType) -> RamenFactory {
        switch type {
        case .Miso: return MisoRamenFactory()
        case .Shoyu: return ShoyuRamenFactory()
        case .Sio: return SioRamenFactory()
        case .Tonkotu: return TonkotuRamenFacroty()
        case .Jiro: return JiroRamenFactory()
        }
    }
    func createSoup(material: String) -> String {
        fatalError("must be overridden")
    }
    
    func createNoodle(flour: String) -> String {
        fatalError("must be overridden")
    }
    
    func createGrilledPork(pork: String) -> String {
        fatalError("must be overridden")
    }
    
    func createOtherTopping(topping: Any) -> Any {
        fatalError("must be overridden")
    }
}

ラーメン職人

コードが長くなってしまうため味噌ラーメンを作る職人(ファクトリークラス)だけ実装しました。スーパークラス(看板娘)の持っていたメソッドをオーバーライドして味噌ラーメンの部品を作る処理を記述しています。

本来はそれぞれのメソッド内でスープクラスや麺クラスを作成すると思うのですが、コードが複雑になってしまい理解しにくくなってしまうかと思い省略しています。

class MisoRamenFactory: RamenFactory {
    override func createSoup(material: String) -> String {
        //秘伝のスープを作成する処理
        return "秘伝のこってり\(material)スープ"
    }
    
    override func createNoodle(flour: String) -> String {
        //自家製面を作る処理
        return "\(flour)で作った自家製麺!!"
    }
    
    override func createGrilledPork(pork: String) -> String {
        //焼豚を作るいろんな処理
        return "\(pork)をじっくり熟成させた焼豚"
        
    }
    
    override func createOtherTopping(topping: Any) -> Any {
        //トッピングを作る処理
        return "\(topping)をトッピング!"
    }
}
class ShoyuRamenFactory: RamenFactory {}
class SioRamenFactory: RamenFactory {}
class TonkotuRamenFacroty: RamenFactory {}
class JiroRamenFactory: RamenFactory {}

呼び出し元

呼び出し元ではこのように呼び出すことでラーメンの形成する部品の作成を行うことができます。

//Factory(ラーメン職人)を作成
var ramenCock = RamenFactory()
print(ramenCock.createRamen(type: .Miso).createSoup(material: "味噌"))
print(ramenCock.createRamen(type: .Miso).createNoodle(flour: "北海道産小麦粉使用"))
print(ramenCock.createRamen(type: .Miso).createGrilledPork(pork: "三元豚"))
print(ramenCock.createRamen(type: .Miso).createOtherTopping(topping: "ネギとコーン"))

コード一覧

import UIKit

enum RamenType {
    case Miso
    case Shoyu
    case Sio
    case Tonkotu
    case Jiro
}

protocol Ramen {
    func createSoup(material: String) -> String
    func createNoodle(flour: String) -> String
    func createGrilledPork(pork: String) -> String
    func createOtherTopping(topping: Any) -> Any
}

class RamenFactory:Ramen {
    
    func createRamen(type: RamenType) -> RamenFactory {
        switch type {
        case .Miso: return MisoRamenFactory()
        case .Shoyu: return ShoyuRamenFactory()
        case .Sio: return SioRamenFactory()
        case .Tonkotu: return TonkotuRamenFacroty()
        case .Jiro: return JiroRamenFactory()
        }
    }
    func createSoup(material: String) -> String {
        fatalError("must be overridden")
    }
    
    func createNoodle(flour: String) -> String {
        fatalError("must be overridden")
    }
    
    func createGrilledPork(pork: String) -> String {
        fatalError("must be overridden")
    }
    
    func createOtherTopping(topping: Any) -> Any {
        fatalError("must be overridden")
    }
}
class MisoRamenFactory: RamenFactory {
    override func createSoup(material: String) -> String {
        //秘伝のスープを作成する処理
        return "秘伝のこってり\(material)スープ"
    }
    
    override func createNoodle(flour: String) -> String {
        //自家製面を作る処理
        return "\(flour)で作った自家製麺!!"
    }
    
    override func createGrilledPork(pork: String) -> String {
        //焼豚を作るいろんな処理
        return "\(pork)をじっくり熟成させた焼豚"
        
    }
    
    override func createOtherTopping(topping: Any) -> Any {
        //トッピングを乗せる処理
        return "\(topping)をトッピング!"
    }
}
class ShoyuRamenFactory: RamenFactory {}
class SioRamenFactory: RamenFactory {}
class TonkotuRamenFacroty: RamenFactory {}
class JiroRamenFactory: RamenFactory {}

//Factory(ラーメン職人)を作成
var ramenCock = RamenFactory()
print(ramenCock.createRamen(type: .Miso).createSoup(material: "味噌"))
print(ramenCock.createRamen(type: .Miso).createNoodle(flour: "北海道産小麦粉使用"))
print(ramenCock.createRamen(type: .Miso).createGrilledPork(pork: "三元豚"))
print(ramenCock.createRamen(type: .Miso).createOtherTopping(topping: "ネギとコーン"))

参考文献

Swiftで学ぶデザインパターン12 (Abstract Factoryパターン)

TECHSCORE AbstractFactory パターン

DevelopersIO Abstract Factory

デザインパターン

前の記事

Facade
デザインパターン

次の記事

Factory Method