Intermediate

C-Sharp Design Patterns Prototype

This course is a starting point in the Prototype Design Pattern in C#. No prior experience with design patterns is required to get started.

Table of Contents

  1. Course Overview
  1. Prototype Pattern Implementation
  1. Complete source code
  1. Summary and key points

1. Course Overview

1.1 Introduction and objectives

Welcome to the course C# Design Patterns: Prototype, presented by Harrison Ferrone, software developer and educational author at Paradigm Shift Development.

This course is a starting point in the Prototype Design Pattern in C#. No prior experience with design patterns is required to get started.

Educational objectives: At the end of this course, you will be able to:

  • Identify and analyze practical use cases for the Prototype Pattern
  • Apply the code and skills learned in your own C# projects

1.2 Prerequisites

As this is an intermediate level course, you should be familiar with:

  • The C# programming language
  • The Visual Studio environment (Mac or Windows)

1.3 Topics covered

The main topics covered in this course are:

SubjectDescription
FoodOrder classDefine a Food Order Object Class
Copy/Clone interfaceAdd a copy and clone interface
Concrete cloning classCreate a concrete clone class
Shallow vs. Deep CopyDifferentiate between shallow and deep copy
Use casesUse cases and practical applications

2. Implementation of the Prototype Pattern

2.1 The Prototype Pattern explained

General context of Design Patterns

Design patterns are classified into three different categories, as defined by the Gang of Four text on elements of reusable object-oriented software:

┌─────────────────────────────────────────────────────┐
│              Catégories de Design Patterns           │
├─────────────────┬──────────────────┬────────────────┤
│   CRÉATIONNELS  │   STRUCTURELS    │  COMPORTEMENTAUX│
│  (Creational)   │  (Structural)    │  (Behavioral)  │
├─────────────────┼──────────────────┼────────────────┤
│ • Prototype     │ • Adapter        │ • Observer     │
│ • Singleton     │ • Bridge         │ • Strategy     │
│ • Factory       │ • Composite      │ • Command      │
│ • Builder       │ • Decorator      │ • Iterator     │
│ • Abstract Fct  │ • Facade         │ • Chain of Res.│
└─────────────────┴──────────────────┴────────────────┘

The Prototype Pattern — Category: Creational

The Prototype Pattern belongs to the Creative category. Its formal definition is:

It specifies the types of objects to create using a prototypical instance and creates new objects by copying this prototype.

At a high level: This pattern allows a client to request a clone of an existing object from the object itself.

On a smaller scale: This pattern can reduce your subclass hierarchy by allowing you to create configurable clones of existing classes instead of creating new subclasses.

When to use the Prototype Pattern?

You should implement the Prototype Pattern when:

  • Object creation, composition and representation must be separated from a given system
  • The classes to be instantiated are specified at execution (runtime)
  • You want to avoid a factory hierarchy that reflects the class hierarchy of your products
  • Class instances can only have a limited and finite combination of states

2.2 UML Diagram of the Prototype Pattern

The UML diagram of the Prototype Pattern is relatively simple. It has three main components:

┌─────────────────────────────────────────────────────────────┐
│                   PROTOTYPE PATTERN UML                      │
└─────────────────────────────────────────────────────────────┘

        ┌──────────────────────┐
        │    <<abstract>>      │
        │      Prototype       │
        ├──────────────────────┤
        │ + ShallowCopy()      │◄─── Méthode blueprint pour
        │ + DeepCopy()         │     toutes les classes adoptantes
        │ + Debug()            │
        └──────────┬───────────┘
                   │ hérite de
                   │
        ┌──────────▼───────────┐
        │  ConcretePrototype   │
        │   (ex: FoodOrder)    │
        ├──────────────────────┤
        │ + ShallowCopy()      │◄─── Chaque classe est responsable
        │ + DeepCopy()         │     de se cloner elle-même
        │ + Debug()            │
        └──────────────────────┘
                   ▲
                   │ utilise
                   │
        ┌──────────┴───────────┐
        │        Client        │
        ├──────────────────────┤
        │                      │◄─── Fait la demande de clonage
        │ object.Clone()       │     depuis l'objet existant
        └──────────────────────┘

Description of components:

  1. Prototype (abstract class): Defines the Clone method as blueprint for all adopting classes. In our implementation, it is an abstract class with methods ShallowCopy(), DeepCopy() and Debug().

  2. ConcretePrototype (concrete classes): As many “clonable” classes as necessary, each responsible for cloning itself and returning a copy on request.

  3. Client: Performs the clone request from an existing object that implements the Prototype interface.

2.3 Creating the Order class

Example scenario

The scenario used for this course is that of a food ordering application. A handy feature of this app would be the copying of favorite food orders that customers have already saved.

Project implementation

  1. Open Visual Studio
  2. Create a new console application (Console Application) in C#
  3. Name the project: Prototype Pattern
  4. Add a new class: FoodOrder.cs

Properties of the FoodOrder class

The FoodOrder class is simple but includes several essential properties:

public class FoodOrder : Prototype
{
    public string customerName;   // Nom du client
    public bool isDelivery;       // Livraison ou retrait en magasin
    public string[] orderContents; // Contenu de la commande (tableau de chaînes)
    public OrderInfo info;         // Informations supplémentaires (référence à un objet)
}

Design note: Properties are declared public to simplify the example. Nothing prevents you from using private variables with public backing properties in this pattern.

Constructor of the FoodOrder class

public FoodOrder(string name, bool delivery, string[] contents, OrderInfo info)
{
    this.customerName = name;
    this.isDelivery = delivery;
    this.orderContents = contents;
    this.info = info;
}

Debug Method

A Debug() method is added to view the status of commands during cloning:

public override void Debug()
{
    Console.WriteLine("------- Prototype Food Order -------");
    Console.WriteLine("\nName: {0} \nDelivery: {1}", this.customerName, this.isDelivery);
    Console.WriteLine("ID: {0}", this.info.id);
    Console.WriteLine("Order Contents: " + string.Join(",", orderContents) + "\n");
}

OrderInfo class — Reference type

To demonstrate the difference between Shallow Copy and Deep Copy, an OrderInfo class is introduced. It represents a reference type:

public class OrderInfo
{
    public int id;

    public OrderInfo(int id)
    {
        this.id = id;
    }
}

Initial usage example

FoodOrder savedOrder = new FoodOrder(
    "Harrison",
    true,
    new string[] { "Pizza", "Coke" },
    new OrderInfo(2345)
);
savedOrder.Debug();

Expected console output:

------- Prototype Food Order -------

Name: Harrison
Delivery: True
ID: 2345
Order Contents: Pizza,Coke

2.4 Implementing object copy

The Prototype abstract class

To enable cloning, an abstract class Prototype is defined. All cloneable classes must inherit it:

public abstract class Prototype
{
    public abstract Prototype ShallowCopy();
    public abstract Prototype DeepCopy();
    public abstract void Debug();
}

Why include Debug() in the abstract class?

Although Debug() is already implemented in FoodOrder, keeping it in the abstract class forces all prototypable classes to include it. This ensures consistency and improves readability for the entire development team.

FoodOrder inherits from Prototype:

public class FoodOrder : Prototype
{
    // ...
}

2.5 Shallow Copy vs Deep Copy

Shallow Copy

What is MemberwiseClone?

The MemberwiseClone method returns a shallow copy of the current object. It is available on all objects in C# (inherited from System.Object).

Behavior of Shallow Copy:

  • All non-static value types are copied to the clone
  • For reference types, only the memory address is copied (not the object itself)
┌─────────────────────────────────────────────────────────────┐
│                     SHALLOW COPY                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Original                    Clone (Shallow)                 │
│  ┌──────────────────┐        ┌──────────────────┐           │
│  │ customerName:"A" │ ──────►│ customerName:"A" │  (copié)  │
│  │ isDelivery: true │ ──────►│ isDelivery: true │  (copié)  │
│  │ orderContents[]  │ ──────►│ orderContents[]  │  (copié)  │
│  │ info ──────────┐ │        │ info ──────────┐ │           │
│  └────────────────│─┘        └────────────────│─┘           │
│                   └──────────────────────────►│             │
│                          même référence !     │             │
│                        ┌─────────────────────▼──┐           │
│                        │   OrderInfo { id: 2345 }│           │
│                        └────────────────────────┘           │
│                                                              │
│  ⚠️ Modifier info.id sur l'original AFFECTE aussi le clone ! │
└─────────────────────────────────────────────────────────────┘
Implementing ShallowCopy
public override Prototype ShallowCopy()
{
    return (Prototype)this.MemberwiseClone();
}
Shallow Copy issue demonstration
// Ordre original
FoodOrder savedOrder = new FoodOrder(
    "Harrison",
    true,
    new string[] { "Pizza", "Coke" },
    new OrderInfo(2345)
);

// Clone superficiel
FoodOrder clonedOrder = (FoodOrder)savedOrder.ShallowCopy();

// Modifications sur l'original
savedOrder.customerName = "Jeff";    // ✅ N'affecte PAS le clone
savedOrder.info.id = 5555;           // ❌ AFFECTE aussi le clone !

savedOrder.Debug();   // Name: Jeff, ID: 5555
clonedOrder.Debug();  // Name: Harrison, ID: 5555  ← problème !

Console output:

------- Prototype Food Order -------
Name: Jeff 
Delivery: True
ID: 5555
Order Contents: Pizza,Coke

------- Prototype Food Order -------
Name: Harrison       ← ✅ La chaîne n'est pas affectée
Delivery: True
ID: 5555             ← ❌ L'ID a été modifié dans le clone aussi !
Order Contents: Pizza,Coke

Important: string are technically reference types in C#, but in this case they transfer correctly during a shallow copy (they are treated as immutable values).

Deep Copy

Purpose of Deep Copy

Deep Copy solves the Shallow Copy problem by creating a new instance for each reference type, so that the original and the clone are completely independent.

┌─────────────────────────────────────────────────────────────┐
│                      DEEP COPY                               │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Original                    Clone (Deep)                    │
│  ┌──────────────────┐        ┌──────────────────┐           │
│  │ customerName:"A" │ ──────►│ customerName:"A" │  (copié)  │
│  │ isDelivery: true │ ──────►│ isDelivery: true │  (copié)  │
│  │ orderContents[]  │ ──────►│ orderContents[]  │  (copié)  │
│  │ info ──────────┐ │        │ info ──────────┐ │           │
│  └────────────────│─┘        └────────────────│─┘           │
│                   │                           │             │
│  ┌────────────────▼──┐    ┌───────────────────▼──┐         │
│  │ OrderInfo{id:2345}│    │ OrderInfo{id:2345}    │         │
│  └───────────────────┘    └──────────────────────┘         │
│        INSTANCE 1                INSTANCE 2                  │
│                                                              │
│  ✅ Modifier info.id sur l'original n'affecte PAS le clone ! │
└─────────────────────────────────────────────────────────────┘
Approaches to implementing Deep Copy

There are several ways to implement Deep Copy. The simplest is to add a DeepCopy() method to the Prototype class and manually re-configure the reference types after creating a shallow clone.

Implementing DeepCopy
public override Prototype DeepCopy()
{
    // Étape 1 : Créer un clone superficiel pour les types valeur
    FoodOrder clonedOrder = (FoodOrder)this.MemberwiseClone();
    
    // Étape 2 : Créer une nouvelle instance pour les types référence
    clonedOrder.info = new OrderInfo(this.info.id);
    
    return clonedOrder;
}

Why not call ShallowCopy() from DeepCopy()? In most cases you will not have both methods in your program. You will choose the one that meets your needs. It is therefore better to keep them completely separate.

Deep Copy Demonstration
// Ordre original
FoodOrder savedOrder = new FoodOrder(
    "Harrison",
    true,
    new string[] { "Pizza", "Coke" },
    new OrderInfo(2345)
);

// Clone profond
FoodOrder clonedOrder = (FoodOrder)savedOrder.DeepCopy();

// Modifications sur l'original
savedOrder.customerName = "Jeff";   // ✅ N'affecte PAS le clone
savedOrder.info.id = 5555;          // ✅ N'affecte PAS le clone

savedOrder.Debug();   // Name: Jeff, ID: 5555
clonedOrder.Debug();  // Name: Harrison, ID: 2345  ← ✅ intact !

Console output:

------- Prototype Food Order -------
Name: Jeff 
Delivery: True
ID: 5555
Order Contents: Pizza,Coke

------- Prototype Food Order -------
Name: Harrison       ← ✅ Non affecté
Delivery: True
ID: 2345             ← ✅ Non affecté non plus !
Order Contents: Pizza,Coke

Shallow Copy vs Deep Copy Comparison

CharacteristicShallow CopyDeep Copy
Value types✅ Copied independently✅ Copied independently
Reference types❌ Same memory address✅ New instance created
Modification of the originalMay affect the cloneDoes not affect the clone
C# methodMemberwiseClone()MemberwiseClone() + manual recreation of referenced objects
Use casesObjects without reference typesObjects with reference types
ComplexitySimpleRequires more code

2.6 Adding a Prototype Manager

Why a Prototype Manager?

The Prototype Manager is an important variation that you will often encounter with the Prototype Pattern. Its role is:

  • Keep track of a prototype object dictionary by key-value pair
  • Facilitate reference by customer code
  • Eliminate the need to create objects on the fly

Implementation of the PrototypeManager class

public class PrototypeManager
{
    // Dictionnaire privé pour stocker les prototypes
    private Dictionary<string, Prototype> _prototypeLibrary = new Dictionary<string, Prototype>();
    
    // Indexeur pour accéder aux prototypes par clé string
    public Prototype this[string key]
    {
        get { return _prototypeLibrary[key]; }
        set { _prototypeLibrary.Add(key, value); }
    }
}

Key implementation points:

  1. Private dictionary _prototypeLibrary: Stores prototypes with a string key and a Prototype type value
  2. Indexer: Allows clean syntactic access and modification via manager["key"]
  3. No explicit constructor: For this example, the objects are added manually via the indexer. You could absolutely declare a constructor that initializes the PrototypeManager with the objects you want to store.

Using the PrototypeManager

// Création du manager
PrototypeManager manager = new PrototypeManager();

// Ajout d'une commande indexée par date
manager["2/3/2020"] = new FoodOrder(
    "Steve",
    false,  // Pas de livraison (retrait en magasin)
    new string[] { "Chicken Parm", "Root Beer" },
    new OrderInfo(8912)
);

// Récupération et clonage profond depuis le manager
Console.WriteLine("Manager clone:");
FoodOrder managerOrder = (FoodOrder)manager["2/3/2020"].DeepCopy();
managerOrder.Debug();

Expected console output:

Manager clone:
------- Prototype Food Order -------

Name: Steve 
Delivery: False
ID: 8912
Order Contents: Chicken Parm,Root Beer

Benefits of Prototype Manager

  1. Scalability: This approach scales very well to a large number of prototype objects, especially if you pass commands to the PrototypeManager during initialization.

  2. Compatibility: The Object Pool pattern works extremely well with the Prototype, especially if it has a manager class.

  3. Flexibility: Although this example only uses a single prototype object, it doesn’t have to be this way. The whole point of the abstract Prototype class is that it can be applied to an indefinite number of objects that we might want to copy. Everything we’ve done will work just fine with a variety of different prototype objects, provided they all inherit from the Prototype class and implement their own cloning and debugging methods.

Sequence diagram — Using the PrototypeManager

Client          PrototypeManager         FoodOrder (Prototype)
  │                    │                         │
  │  manager["key"] =  │                         │
  │  new FoodOrder(...)│                         │
  │───────────────────►│                         │
  │                    │── _prototypeLibrary.Add()│
  │                    │                         │
  │  manager["key"]    │                         │
  │  .DeepCopy()       │                         │
  │───────────────────►│                         │
  │                    │── _prototypeLibrary[key] │
  │                    │────────────────────────►│
  │                    │                         │── MemberwiseClone()
  │                    │                         │── new OrderInfo(id)
  │                    │◄────── clone ───────────│
  │◄── clone ──────────│                         │
  │                    │                         │
  │  clone.Debug()     │                         │
  │───────────────────────────────────────────►  │

2.7 Use cases and implications

Common application scenarios

The Prototype Pattern is particularly suitable in the following situations:

  1. Classes instantiated at runtime: When the classes to be instantiated are dynamically specified during program execution, not during compilation.

  2. Avoiding a factory hierarchy: When you want to avoid a factory class hierarchy that would mirror the class hierarchy of your products.

  3. Limited state combinations: When class instances can only have a limited and finite number of state combinations.

Golden rule: Like all design patterns, implementing each object in your project as a prototype is not the right approach and can even be excessive. The main thing is to find the places where it really makes sense and use it correctly.

Comparison with other creational patterns

If you are familiar with other creative patterns, notably Builder and Abstract Factory, you will probably have noticed that they share several implications with the Prototype:

InvolvementPrototypeBuilderAbstract Factory
Hidden client concrete classes
Products that can be added/removed at runtime
Dynamic Object CompositionPartial
Reduced class hierarchy
Usable as a component in a larger design

Four key implications of the Prototype Pattern

  1. Concrete classes hidden from the client: The client code does not need to know the concrete classes; it only works with the abstract interface Prototype.

  2. Products added/removed at runtime: As already noted, products can be added or removed dynamically by the client.

  3. More dynamic system via object composition: Using cloned objects with varied configurations makes your system more dynamic through this type of object composition, and your class hierarchy will be cleaner and more efficient.

  4. Increased Modularity: Prototype objects can be used as components in a larger object creation design, which can also increase the modularity of your code.


3. Full source code

3.1 FoodOrder.cs

This file contains all the classes of the Prototype Pattern: the abstract class Prototype, the class OrderInfo, the concrete class FoodOrder and the PrototypeManager.

using System;
using System.Collections.Generic;
using System.Text;

namespace Prototype_Pattern
{
    // Classe abstraite définissant le contrat de clonage
    public abstract class Prototype
    {
        public abstract Prototype ShallowCopy();
        public abstract Prototype DeepCopy();
        public abstract void Debug();
    }

    // Type référence pour démontrer la différence Shallow/Deep Copy
    public class OrderInfo
    {
        public int id;

        public OrderInfo(int id)
        {
            this.id = id;
        }
    }

    // Classe concrète prototypable — hérite de Prototype
    public class FoodOrder : Prototype
    {
        public string customerName;
        public bool isDelivery;
        public string[] orderContents;
        public OrderInfo info;  // ← Type référence !

        public FoodOrder(string name, bool delivery, string[] contents, OrderInfo info)
        {
            this.customerName = name;
            this.isDelivery = delivery;
            this.orderContents = contents;
            this.info = info;
        }

        // Copie superficielle : les types référence partagent la même adresse
        public override Prototype ShallowCopy()
        {
            return (Prototype)this.MemberwiseClone();
        }

        // Copie profonde : tous les types référence sont recréés
        public override Prototype DeepCopy()
        {
            FoodOrder clonedOrder = (FoodOrder)this.MemberwiseClone();
            clonedOrder.info = new OrderInfo(this.info.id);  // ← Nouvelle instance !
            return clonedOrder;
        }

        // Méthode de débogage pour visualiser l'état de la commande
        public override void Debug()
        {
            Console.WriteLine("------- Prototype Food Order -------");
            Console.WriteLine("\nName: {0} \nDelivery: {1}", this.customerName, this.isDelivery);
            Console.WriteLine("ID: {0}", this.info.id);
            Console.WriteLine("Order Contents: " + string.Join(",", orderContents) + "\n");
        }
    }

    // Variante manager : stocke un dictionnaire de prototypes accessibles par clé
    public class PrototypeManager
    {
        private Dictionary<string, Prototype> _prototypeLibrary = new Dictionary<string, Prototype>();
        
        // Indexeur pour accès et modification syntaxiques
        public Prototype this[string key]
        {
            get { return _prototypeLibrary[key]; }
            set { _prototypeLibrary.Add(key, value); }
        }
    }
}

3.2 Program.cs

The main program demonstrates the use of the PrototypeManager with DeepCopy().

using System;

namespace Prototype_Pattern
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
             * Exemple de Shallow Copy vs Deep Copy (code commenté) :
             *
             * Console.WriteLine("Original order:");
             * FoodOrder savedOrder = new FoodOrder(
             *     "Harrison",
             *     true,
             *     new string[] { "Pizza", "Coke"},
             *     new OrderInfo(2345)
             * );
             * savedOrder.Debug();
             *
             * Console.WriteLine("Cloned order:");
             * FoodOrder clonedOrder = (FoodOrder)savedOrder.DeepCopy();
             * clonedOrder.Debug();
             *
             * Console.WriteLine("Order changes:");
             * savedOrder.customerName = "Jeff";
             * savedOrder.info.id = 5555;
             * savedOrder.Debug();
             * clonedOrder.Debug();
             */

            // === Utilisation du PrototypeManager ===
            PrototypeManager manager = new PrototypeManager();
            
            // Ajout d'une commande indexée par date
            manager["2/3/2020"] = new FoodOrder(
                "Steve",
                false,
                new string[] { "Chicken Parm", "Root Beer" },
                new OrderInfo(8912)
            );

            // Récupération et clonage depuis le manager
            Console.WriteLine("Manager clone:");
            FoodOrder managerOrder = (FoodOrder)manager["2/3/2020"].DeepCopy();
            managerOrder.Debug();
        }
    }
}

Program console output:

Manager clone:
------- Prototype Food Order -------

Name: Steve 
Delivery: False
ID: 8912
Order Contents: Chicken Parm,Root Beer

4. Summary and key points

What we learned

  1. Create a Prototype abstract class which imposes a cloning blueprint on the adopting classes.

  2. Distinguish and implement Shallow Copy and Deep Copy:

  • Shallow Copy uses MemberwiseClone() and copies addresses of reference types
  • Deep Copy uses MemberwiseClone() and manually recreates instances of reference types
  1. Configure a Prototype Manager to store and retrieve prototype objects more efficiently via a key-indexed dictionary.

  2. Identify and work with the Prototype Pattern in real-world scenarios, including control applications, object configuration systems, and architectures requiring dynamic composition.

Overall architecture of the pattern

┌──────────────────────────────────────────────────────────────────┐
│                  PROTOTYPE PATTERN — Vue globale                  │
├──────────────────────────────────────────────────────────────────┤
│                                                                    │
│  ┌─────────────────────────────────────────────────────────┐     │
│  │              Namespace: Prototype_Pattern                │     │
│  │                                                          │     │
│  │  ┌──────────────────┐    ┌──────────────────────────┐   │     │
│  │  │  <<abstract>>    │    │    PrototypeManager       │   │     │
│  │  │    Prototype     │    │  ─────────────────────    │   │     │
│  │  │ ─────────────    │    │  -_prototypeLibrary:      │   │     │
│  │  │ +ShallowCopy()   │    │   Dictionary<str,Prot>    │   │     │
│  │  │ +DeepCopy()      │    │  ─────────────────────    │   │     │
│  │  │ +Debug()         │    │  +this[string key]        │   │     │
│  │  └────────┬─────────┘    └──────────────────────────┘   │     │
│  │           │ hérite                    │ contient         │     │
│  │  ┌────────▼────────────┐             │                   │     │
│  │  │     FoodOrder        │◄────────────┘                   │     │
│  │  │ ──────────────────  │                                  │     │
│  │  │ +customerName:string│    ┌─────────────────────────┐  │     │
│  │  │ +isDelivery:bool    │    │       OrderInfo          │  │     │
│  │  │ +orderContents:str[]│    │ ──────────────────────── │  │     │
│  │  │ +info:OrderInfo ────┼───►│ +id:int                  │  │     │
│  │  │ ──────────────────  │    │ ──────────────────────── │  │     │
│  │  │ +ShallowCopy()      │    │ +OrderInfo(id:int)        │  │     │
│  │  │ +DeepCopy()         │    └─────────────────────────┘  │     │
│  │  │ +Debug()            │                                  │     │
│  │  └─────────────────────┘                                  │     │
│  └──────────────────────────────────────────────────────────┘     │
└──────────────────────────────────────────────────────────────────┘

Implementation Checklist

Before implementing the Prototype Pattern, check the following:

  • Object creation, composition and representation must be separated from the system
  • Classes have configurations that vary slightly from instance to instance
  • Creating objects is costly (in time or resources)
  • You need independence between original and clone
  • You have identified whether you need Shallow Copy or Deep Copy

Best practices

  1. Choice between Shallow and Deep Copy: Analyze your objects. If all fields are value types (int, bool, struct), a Shallow Copy is sufficient. If reference types are present, use Deep Copy.

  2. Prototype Manager: Use a PrototypeManager whenever you have several prototypes to manage or when objects must be accessible from several places in the code.

  3. Pattern Object Pool: This pattern works extremely well with the Prototype, especially if the latter has a manager class.

  4. Don’t overdo it: Implementing every object in your project as a prototype is excessive. Identify cases where creating new objects through cloning provides real value.

  5. Debug method: Always include a Debug() method in your abstract Prototype class to force all concrete classes to offer diagnostic capability.



Search Terms

c-sharp · design · patterns · prototype · testing · architecture · c# · .net · development · copy · pattern · class · deep · shallow · manager · prototypemanager · comparison · creational · demonstration · diagram · foodorder · implications

Interested in this course?

Contact us to book it or get a custom training plan for your team.