この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Abstract Factory
Abstract Factory とは
日本語では「抽象的な工場」と訳されることが多いらしいです。
Abstract Factory は互いに関連したり依存し合うオブジェクト群を、その具象クラスを明確にせずに生成するためのインタフェースを提供するパターンです。
クラス図
ポイント
- ファクトリークラスごとに、生成するプロダクトが決まっている
- 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 型であると推論されている場合は、型名を省略し .<メンバ名> と記述することができる