Design Pattern: Prototype - using GoLang

Jayaprasanna Roddam - Nov 6 - - Dev Community

The Prototype Pattern is a creational design pattern that allows for creating new objects by copying existing instances (prototypes) rather than instantiating new ones from scratch. This pattern is particularly useful when the cost of creating an object from scratch is expensive (e.g., due to complex setup or resource-intensive initialization), or when you want to avoid subclasses for every possible configuration of an object.

Key Concepts of the Prototype Pattern

  1. Prototype Interface: Defines a Clone method to create a copy of the object. This interface is implemented by classes that need to support cloning.
  2. Concrete Prototype: An object that implements the Clone method, allowing it to create a copy of itself.
  3. Client Code: Uses the prototype to clone new instances instead of creating them directly, ensuring flexibility in the types of objects it works with.

Example Use Case in Go

Imagine a scenario where we have different types of shapes (Circle, Rectangle) with various properties. Instead of recreating these shapes, we can clone an existing shape and modify only the necessary attributes.

Code Example in Go

package main

import (
    "fmt"
)

// Shape defines the prototype interface with a Clone method.
type Shape interface {
    Clone() Shape
    GetInfo() string
}

// Circle represents a concrete prototype implementing Shape.
type Circle struct {
    Radius int
    Color  string
}

// Clone creates a copy of the Circle with the same properties.
func (c *Circle) Clone() Shape {
    return &Circle{Radius: c.Radius, Color: c.Color}
}

// GetInfo provides information about the Circle.
func (c *Circle) GetInfo() string {
    return fmt.Sprintf("Circle with radius %d and color %s", c.Radius, c.Color)
}

// Rectangle represents another concrete prototype implementing Shape.
type Rectangle struct {
    Width  int
    Height int
    Color  string
}

// Clone creates a copy of the Rectangle with the same properties.
func (r *Rectangle) Clone() Shape {
    return &Rectangle{Width: r.Width, Height: r.Height, Color: r.Color}
}

// GetInfo provides information about the Rectangle.
func (r *Rectangle) GetInfo() string {
    return fmt.Sprintf("Rectangle with width %d, height %d, and color %s", r.Width, r.Height, r.Color)
}

func main() {
    // Original shapes
    circle := &Circle{Radius: 10, Color: "Red"}
    rectangle := &Rectangle{Width: 5, Height: 10, Color: "Blue"}

    // Clone shapes
    clonedCircle := circle.Clone()
    clonedRectangle := rectangle.Clone()

    fmt.Println(clonedCircle.GetInfo())  // Output: Circle with radius 10 and color Red
    fmt.Println(clonedRectangle.GetInfo()) // Output: Rectangle with width 5, height 10, and color Blue
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  • Prototype Interface (Shape): Defines a Clone() method, which each concrete prototype implements to return a copy of itself.
  • Concrete Prototypes (Circle, Rectangle): Implement the Clone() method to return copies of their own instances with the same properties.
  • Client Code: Calls Clone() on existing instances (e.g., circle.Clone()) to create new objects without needing to know their exact types, making it flexible and efficient.

Benefits of the Prototype Pattern

  1. Efficiency: Reduces the cost of creating new instances by cloning existing ones, which is particularly useful for resource-intensive objects.
  2. Decoupling: Clients are decoupled from specific classes, allowing them to work with prototypes generically.
  3. Flexibility: Allows for easy creation of customized objects by cloning and tweaking properties on the cloned instance, without affecting the original.

The Prototype Pattern is ideal when object creation is costly or when you need flexibility in creating variations of an object based on an existing template.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .