DEV Community

Dzung Nguyen
Dzung Nguyen

Posted on • Edited on

Prototype Design Pattern Explained

What is the Prototype Design Pattern?
The Prototype design pattern allows you to clone an existing object to create new objects, rather than instantiating them directly. This pattern is particularly useful when object creation is complex, time-consuming, or expensive.

Prototype Design Pattern

When Should You Use the Prototype Pattern?
The Prototype Design Pattern is ideal for scenarios where:

  • Object Creation is Expensive: For example, when constructing large graphs, initializing a database connection, or creating complex objects with many dependencies.

  • Need for Similar Objects: You need to create multiple objects with slightly different configurations.

  • Dynamic Object Types: The object type may not be known until runtime.

How Does it Work?

The Prototype pattern relies on two key elements:

  • Prototype Interface: Defines the method for cloning objects.
  • Concrete Prototypes: Classes that implement the cloning method.

Below is a class diagram representing the Prototype design pattern:

Prototype Diagram

Prototype Pattern Example in Golang: Game Character Cloning

In multiplayer games, players often select a base character (e.g., warrior, mage, or archer) and customize their abilities, weapons, or outfits. Instead of creating each character from scratch, we can use the Prototype design pattern to clone base character templates and tweak them for each player.

Here’s how the Prototype design pattern can be used to create different game characters:

Implementation

package prototype

import "fmt"

// Prototype interface
type Prototype interface {
    Clone() Prototype
    GetDetails() string
}

// Concrete Prototype: GameCharacter
type GameCharacter struct {
    Name       string
    Class      string
    Level      int
    Health     int
    Stamina    int
    Weapon     string
    Armor      string
    Speciality string
}

// Clone method creates a copy of the GameCharacter
func (c *GameCharacter) Clone() Prototype {
    return &GameCharacter{
        Name:       c.Name,
        Class:      c.Class,
        Level:      c.Level,
        Health:     c.Health,
        Stamina:    c.Stamina,
        Weapon:     c.Weapon,
        Armor:      c.Armor,
        Speciality: c.Speciality,
    }
}

// GetDetails provides a summary of the GameCharacter
func (c *GameCharacter) GetDetails() string {
    return fmt.Sprintf("Name: %s, Class: %s, Level: %d, Health: %d, Stamina: %d, Weapon: %s, Armor: %s, Speciality: %s",
        c.Name, c.Class, c.Level, c.Health, c.Stamina, c.Weapon, c.Armor, c.Speciality)
}
Enter fullscreen mode Exit fullscreen mode
package main

import (
    "example.com/prototype"
    "fmt"
)

func main() {
    // Create a base character template for a Warrior
    warriorTemplate := &prototype.GameCharacter{
        Name:       "Base Warrior",
        Class:      "Warrior",
        Level:      1,
        Health:     100,
        Stamina:    50,
        Weapon:     "Sword",
        Armor:      "Steel Armor",
        Speciality: "Melee Combat",
    }

    // Clone and customize for Player 1
    player1 := warriorTemplate.Clone().(*prototype.GameCharacter)
    player1.Name = "Arthas"
    player1.Level = 10
    player1.Weapon = "Frostmourne"

    // Clone and customize for Player 2
    player2 := warriorTemplate.Clone().(*prototype.GameCharacter)
    player2.Name = "Leonidas"
    player2.Level = 8
    player2.Weapon = "Spear"
    player2.Armor = "Golden Armor"

    // Print details of the base character and the cloned characters
    fmt.Println("Base Character Template:")
    fmt.Println(warriorTemplate.GetDetails())

    fmt.Println("\nPlayer 1 Character:")
    fmt.Println(player1.GetDetails())

    fmt.Println("\nPlayer 2 Character:")
    fmt.Println(player2.GetDetails())
}
Enter fullscreen mode Exit fullscreen mode

Output

Base Character Template:
Name: Base Warrior, Class: Warrior, Level: 1, Health: 100, Stamina: 50, Weapon: Sword, Armor: Steel Armor, Speciality: Melee Combat

Player 1 Character:
Name: Arthas, Class: Warrior, Level: 10, Health: 100, Stamina: 50, Weapon: Frostmourne, Armor: Steel Armor, Speciality: Melee Combat

Player 2 Character:
Name: Leonidas, Class: Warrior, Level: 8, Health: 100, Stamina: 50, Weapon: Spear, Armor: Golden Armor, Speciality: Melee Combat
Enter fullscreen mode Exit fullscreen mode

From the above example, we can draw some key insights:

  • Game Character Templates: Instead of manually setting attributes for every character, you can establish base templates for each character class (e.g., warrior, mage, archer) and use the Prototype pattern to create variations.

  • Customization: By cloning base characters, you can easily modify specific attributes such as name, weapon, level, or armor to suit each player’s needs.

  • Efficiency: This approach simplifies the process of creating unique objects while still allowing for extensive customization, reducing overall complexity.

Advantages

  • Reusability: Base objects or templates can be reused across different contexts or scenarios, reducing duplication and simplifying object creation.

  • Efficiency: Speeds up the creation process by cloning pre-configured objects, avoiding the overhead of building objects from scratch.

  • Flexibility: Makes it easy to create customized objects by tweaking cloned instances, allowing for tailored modifications without altering the original template.

Challenges

  • Deep vs. Shallow Copy: When objects contain references to other objects, care must be taken to perform a deep copy to avoid unintended side effects.
  • Interface Dependency: All objects that need to be cloned must implement the Prototype interface, which may not always be feasible.

Conclusion

The Prototype Design Pattern is a powerful tool for optimizing object creation, reducing complexity, and improving performance. Its ability to dynamically clone objects at runtime makes it particularly useful in scenarios where creating objects from scratch is expensive or impractical.

Have you implemented the Prototype pattern in your projects? How did it help streamline your development? Let’s discuss your thoughts and experiences in the comments!


Follow me to stay updated with my future posts:

Top comments (0)