ការបង្កើត កម្រិតស្មុគស្មាញ: មធ្យម

លំនាំ Prototype ក្នុង Go

ចម្លង object graphs ដែលបានកំណត់រួច នៅពេលការចម្លងសាមញ្ញ ឬលឿនជាងការសាងសង់ឡើងវិញពីដើម។

The Problem

Sometimes the expensive part of object creation is not allocating one struct. It is rebuilding a whole preconfigured object graph with nested defaults, collections, and shared setup rules. When that same baseline needs to be reused repeatedly, rebuilding it by hand creates duplication and makes small variations error-prone.

The Solution

The Prototype pattern keeps a fully configured instance around and asks it to clone itself. In Go, that usually means defining a small Clone() contract and being explicit about deep-copy behavior for slices, nested structs, and recursive graphs.

The Go example on Refactoring Guru uses a recursive file-and-folder model to show this idea. This article applies the same deep-cloning approach to commerce bundle templates, where nested bundles and products need to be copied safely before customization.

Structure

  • Prototype interface: CatalogPrototype defines the cloning contract.
  • Concrete prototypes: ProductTemplate and BundleTemplate know how to copy their own state.
  • Registry: TemplateRegistry stores baseline templates and returns cloned copies on demand.
  • Client: Application code clones a stored template and customizes the copy.

Implementation

This example stores a preconfigured launch bundle in a registry, clones it, and then turns the clone into a Black Friday variant without mutating the original nested structure.

package main

// CatalogPrototype defines the common cloning contract.
type CatalogPrototype interface {
	Clone() CatalogPrototype
	Rename(name string)
	Describe(indent string) string
}

Best Practices

  • Be explicit about deep versus shallow copies. Slices, maps, and nested references are where clone bugs usually hide.
  • Keep the clone contract small. A focused Clone() method is easier to reason about than generic reflection-based copying.
  • Use prototypes for expensive or repetitive setup, not for every ordinary constructor.
  • A registry is useful when the same baseline templates are reused often.
  • Avoid sharing mutable internals between the original and the clone unless that sharing is intentional.

When to Use

  • Rebuilding a baseline object graph is repetitive or expensive.
  • You need small variations of the same preconfigured object.
  • The client should not know all the construction details required to recreate the original.

When NOT to Use

  • A plain constructor or factory is already simpler.
  • The object graph is shallow enough that copying manually is clearer.
  • Clone semantics would be ambiguous or dangerous because the object owns external resources like file handles or network connections.