[iOS 8] Swiftでデザインパターン No.8 Abstract Factory

2014.11.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Abstract Factory

Abstract Factory とは

日本語では「抽象的な工場」と訳されることが多いらしいです。

Abstract Factory は互いに関連したり依存し合うオブジェクト群を、その具象クラスを明確にせずに生成するためのインタフェースを提供するパターンです。

クラス図

abstractFactory

ポイント

  • ファクトリークラスごとに、生成するプロダクトが決まっている
    • Product1 を生成するのは ConcreteFactory1
    • Product2 を生成するのは ConcreteFactory2

サンプルコード

Emacs と Vim で、コピー&ペーストを実行するプログラムです。

CommandFactory(AbstractFactory)

enum Editor {
case Emacs
case Vim

func name() -> String {
switch self {
case Emacs: return "Emacs"
case Vim: return "Vim"
}
}
}

class CommandFactory {
class func getFactory(editor: Editor) -> CommandFactory {
switch editor {
case .Emacs: return EmacsCommandFactory()
case .Vim: return VimCommandFactory()
}
}

func createCopy() -> Copy {
fatalError("must be overridden")
}

func createPaste() -> Paste {
fatalError("must be overridden")
}
}

AbstractFactory クラスです。

コマンドを生成する工場を表現する抽象クラスです。 「コピー」と「ペースト」のコマンド(プロダクト)を生成するメソッドを持ちます。 また、適切なファクトリークラスを返すgetFactoryというクラスメソッドも持ちます。このメソッドの引数は enum です。

EmacsCommandFactory(ConcreteFactory1)

class EmacsCommandFactory: CommandFactory {
override func createCopy() -> Copy {
return EmacsCopy()
}

override func createPaste() -> Paste {
return EmacsPaste()
}
}

ConcreteFactory1 クラスです。

createCopy(),createPaste()では、それぞれ Emacs 用のコマンドを返します。

VimCommandFactory(ConcreteFactory2)

class VimCommandFactory: CommandFactory {
override func createCopy() -> Copy {
return VimCopy()
}

override func createPaste() -> Paste {
return VimPaste()
}
}

ConcreteFactory2 クラスです。

createCopy(),createPaste()では、それぞれ Vim 用のコマンドを返します。

Copy(AbstractProductA)

class Copy {
func execute() {}
}

AbstractProductA クラスです。

Copy コマンドを表現する抽象クラスです。 実行メソッドexecute()を持ちます。

EmacsCopy(ProductA1)

class EmacsCopy: Copy {
override func execute() {
println("M-w")
}
}

ProductA1 クラスです。

Emacs の Copy を表現します。

VimCopy(ProductA2)

class VimCopy: Copy {
override func execute() {
println("y")
}
}

ProductA2 クラスです。

Vim の Copy を表現します。

Paste(AbstractProductB)

class Paste {
func execute() {}
}

AbstractProductB クラスです。

Paste コマンドを表現する抽象クラスです。 実行メソッドexecute()を持ちます。

EmacsPaste(ProductB1)

class EmacsPaste: Paste {
override func execute() {
println("C-y")
}
}

ProductB1 クラスです。

Emacs の Paste を表現します。

VimPaste(ProductB2)

class VimPaste: Paste {
override func execute() {
println("p")
}
}

ProductB2 クラスです。

Vim の Paste を表現します。

実行

func main() {
copyAndPaste(.Emacs) // Emacs でコピー&ペースト
copyAndPaste(.Vim) // Vim でコピー&ペースト
}
func copyAndPaste(editor: Editor) {
let commandFactory = CommandFactory.getFactory(editor)

println("### " + editor.name() + " ###")

print("Copy:t")
commandFactory.createCopy().execute()

print("Paste:t")
commandFactory.createPaste().execute()
}

実行結果

### Emacs ###
Copy: M-w
Paste: C-y

### Vim ###
Copy: y
Paste: p

Emacs と Vim のコピー&ペーストでした。

まとめ

  • Swift の enum はメソッドを定義することができる
  • 変数/定数が enum 型であると推論されている場合は、型名を省略し .<メンバ名> と記述することができる

リンク