Welcome To Golang By Example

Prototype Pattern in Go (Golang)

Note: Interested in understanding how all other design patterns can be implemented in GO. Please see this full reference – All Design Patterns in Go (Golang)

Definition:

It is a creational design pattern that lets you create copies of objects. In this pattern, the responsibility of creating the clone objects is delegated to the actual object to clone.

The object to be cloned exposes a clone method which returns a clone copy of the object

When to Use

UML Diagram

Mapping 

The below table represents the mapping from the UML diagram actors to actual implementation actors in code.

prototype interfaceinode.go
Concrete Prototype 1file.go
Concrete Prototype 2folder.go
clientmain.go

Practical Example:

In the context of golang let’s try to understand it with an example of os file system. The os file system has files and folders and folders itself contain files and folders. Each file and folder can be represented by an inode interface. inode interface also has the clone() function.

inode.go

package main

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

file struct is represented as

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 struct is represented as

folder.go

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
}

Since both file and folder struct implements the print and clone functions, hence they are of type inode. 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. While cloning we append the keyword “_clone” for the name field. Let’s write the main function to test things out.

main.go

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:

Printing hierarchy for Folder2
  Folder2
    Folder1
        File1
    File2
    File3

Printing hierarchy for clone Folder
  Folder2_clone
    Folder1_clone
        File1_clone
    File2_clone
    File3_clone