
Prototype を Go で
Prototype は、 生成に関するデザインパターンの一つで、 特定のクラスに結合することなく、 オブジェクト (たとえ複雑なオブジェクトでも) のクローン作成を可能とします。
プロトタイプのクラス全部には、 共通するインターフェースが必要です。 これにより、 具象クラスが不明であってもオブジェクトを複製することが可能となります。 プロトタイプ・オブジェクトが、 完全なコピーを生成できるのは、 同じクラスのオブジェクト同士が非公開フィールドを互いにアクセスできるからです。
概念的な例
オペレーティング・システムのファイル・システムに基づいた例を使い、 Prototype パターンを調べてみましょう。 OS のファイル・システムは再帰的です: フォルダーにはファイルとフォルダーが含まれており、 そのフォルダーには、 ファイルとフォルダーも含まれている、 といった具合です。
個々のファイルおよびフォルダーは、 inode
インターフェースで表現されます。 inode
インターフェースには、 clone
関数があります。
file
構造体と folder
構造体の両方とも、 inode
型をしているので、 print
関数と clone
関数を実装します。 file
と folder
の両方に clone
関数があることにも注目してください。 両方に含まれる clone
関数は、 それぞれファイルかフォルダーのコピーを返します。 クローン作成にあたり、 「name」 フィールドに、 「_clone」 という接尾語を付け足しています。
inode.go: プロトタイプ・インターフェース
package main
type Inode interface {
print(string)
clone() Inode
}
file.go: 具象プロトタイプ
package main
import "fmt"
type File struct {
name string
}
func (f *File) print(indentation string) {
fmt.Println(indentation + f.name)
}
func (f *File) clone() Inode {
return &File{name: f.name + "_clone"}
}
folder.go: 具象プロトタイプ
package main
import "fmt"
type Folder struct {
children []Inode
name string
}
func (f *Folder) print(indentation string) {
fmt.Println(indentation + f.name)
for _, i := range f.children {
i.print(indentation + indentation)
}
}
func (f *Folder) clone() Inode {
cloneFolder := &Folder{name: f.name + "_clone"}
var tempChildren []Inode
for _, i := range f.children {
copy := i.clone()
tempChildren = append(tempChildren, copy)
}
cloneFolder.children = tempChildren
return cloneFolder
}
main.go: クライアント・コード
package main
import "fmt"
func main() {
file1 := &File{name: "File1"}
file2 := &File{name: "File2"}
file3 := &File{name: "File3"}
folder1 := &Folder{
children: []Inode{file1},
name: "Folder1",
}
folder2 := &Folder{
children: []Inode{folder1, file2, file3},
name: "Folder2",
}
fmt.Println("\nPrinting hierarchy for Folder2")
folder2.print(" ")
cloneFolder := folder2.clone()
fmt.Println("\nPrinting hierarchy for clone Folder")
cloneFolder.print(" ")
}
output.txt: 実行結果
Printing hierarchy for Folder2
Folder2
Folder1
File1
File2
File3
Printing hierarchy for clone Folder
Folder2_clone
Folder1_clone
File1_clone
File2_clone
File3_clone