Hooray! After 3 years of work, I've finally released the ebook on design patterns! Check it out »
Prototype

Prototype in Go

Prototype is a creational design pattern that allows cloning objects, even complex ones, without coupling to their specific classes.

All prototype classes should have a common interface that makes it possible to copy objects even if their concrete classes are unknown. Prototype objects can produce full copies since objects of the same class can access each other’s private fields.

Conceptual Example

Let’s try to figure out the Prototype pattern using an example based on the operating system’s file system. The OS file system is recursive: the folders contain files and folders, which may also include files and folders, and so on.

Each file and folder can be represented by an inode interface. inode interface also has the clone function.

Both file and folder structs implement the print and clone functions since they are of the inode type. Also, notice the clone function in both file and folder. The clone function in both of them returns a copy of the respective file or folder. During the cloning, we append the keyword “_clone” for the name field.

inode.go: Prototype interface

package main

type inode interface {
	print(string)
	clone() inode
}

file.go: Concrete prototype

package main

import "fmt"

type file struct {
	name string
}

func (f *file) print(indentation string) {
	fmt.Println(indentation + f.name + "_clone")
}

func (f *file) clone() inode {
	return &file{name: f.name}
}

folder.go: Concrete prototype

package main

import "fmt"

type folder struct {
	childrens []inode
	name      string
}

func (f *folder) print(indentation string) {
	fmt.Println(indentation + f.name)
	for _, i := range f.childrens {
		i.print(indentation + indentation)
	}
}

func (f *folder) clone() inode {
	cloneFolder := &folder{name: f.name + "_clone"}
	var tempChildrens []inode
	for _, i := range f.childrens {
		copy := i.clone()
		tempChildrens = append(tempChildrens, copy)
	}
	cloneFolder.childrens = tempChildrens
	return cloneFolder
}

main.go: Client code

package main

import "fmt"

func main() {
	file1 := &file{name: "File1"}
	file2 := &file{name: "File2"}
	file3 := &file{name: "File3"}

	folder1 := &folder{
		childrens: []inode{file1},
		name:      "Folder1",
	}

	folder2 := &folder{
		childrens: []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: Execution result

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 in Other Languages

Design Patterns: Prototype in Java Design Patterns: Prototype in C# Design Patterns: Prototype in C++ Design Patterns: Prototype in PHP Design Patterns: Prototype in Python Design Patterns: Prototype in Ruby Design Patterns: Prototype in Swift Design Patterns: Prototype in TypeScript