俺の新 Git コース見てよ! おーい!俺の新 Git コース見てよ! おーい!GitByBit.com に俺の新 Git コースあるよ、見てみ! おーい!Git をサクッと復習したい?GitByBit.com の俺の新コース見てみ!
Prototype

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

他言語での Prototype

Prototype を C# で Prototype を C++ で Prototype を Java で Prototype を PHP で Prototype を Python で Prototype を Ruby で Prototype を Rust で Prototype を Swift で Prototype を TypeScript で