C# | Design Patterns — Examples

Karim Samir
simplifycoding
Published in
5 min readMar 28, 2024

Design Patterns in the object-oriented world are a reusable solution to common software design problems that repeatedly occur in real-world application development. It is a template or description of how to solve problems that can be used in many situations.

SINGLETON

The Singleton pattern ensures that a class has only one instance and provides a global point of access to it.

// * * * ** ** ** ** ** ** ** ** ** ** ** ** ** *
public class Singleton
{
private static Singleton? instance;
private Singleton()
{
Console.WriteLine("Singleton is Instantiated.");
}
public static Singleton GetInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
public void DoSomething()
{
Console.WriteLine("Something is Done.");
}
}
// * * * ** ** ** ** ** ** ** ** ** ** ** ** ** *
public static void Main(string[] args)
{
Singleton.GetInstance().DoSomething();
}
// * * * ** ** ** ** ** ** ** ** ** ** ** ** ** *

Example Real Word:

Logger: In many software systems, logging is an essential component for recording events and debugging purposes. A Logger class can manage logging operations throughout the application. It ensures that only one instance of the Logger exists, and all parts of the system can access it easily.

BUILDER PATTERN

Builder Pattern is a creational design pattern, which allows constructing complex objects(with Multiple Properties) step by step.

// * * * ** ** ** ** ** ** ** ** ** ** ** ** ** *
public class Product
{
public string? attri1 { get; set; }
public string? attri2 { get; set; }

public void showInfo()
{
//Show info Product ...
}
}
//* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public interface IBuilder
{
void BuildPart1(string part1Value);
void BuildPart2(string part2Value);
Product GetProduct();
}
//* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public class ConcreteBuilder : IBuilder
{
private Product _product = new Product();

public void BuildPart1(string attr1Value)
{
_product.attri1 = attr1Value;

}

public void BuildPart2(string attr2Value)
{
_product.attri2 = attr2Value;
}

public Product GetProduct()
{
return _product;
}
}
//* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public class Director
{
private readonly ConcreteBuilder objBuilder;

public Director(ConcreteBuilder objBuilder)
{
this.objBuilder = objBuilder;
}
public void Construct(object? FromForm)
{
// ["Part 1"/"Part 2"] is the values that you receive -->
//from a Form. For example: FromForm.Username or FromForm.Password etc.
objBuilder.BuildPart1("Part 1");
objBuilder.BuildPart2("Part 2");
}
public Product GetVehicle()
{
return objBuilder.GetProduct();
}
}
//* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public class Usage
{
public void program()
{
var _director = new Director(new ConcreteBuilder());
_director.Construct(null);
var product = _director.GetVehicle();
product.showInfo();
}
}

Proxy Pattern

is a structural design pattern. You’re architecting a complex software system, and you need a guardian for your objects(Don’t touch the Real Object)

// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public interface IMath
{
double Add(double x, double y);
double Sub(double x, double y);
double Mul(double x, double y);
double Div(double x, double y);
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public class RealMath : IMath
{
public double Add(double x, double y) { return x + y; }
public double Sub(double x, double y) { return x - y; }
public double Mul(double x, double y) { return x * y; }
public double Div(double x, double y) { return x / y; }
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public class ProxyMath : IMath
{
private RealMath math = new RealMath();

public double Add(double x, double y)
{
return math.Add(x, y);
}

// We won't gave acces to SuB Function

public double Mul(double x, double y)
{
return math.Mul(x, y);
}
public double Div(double x, double y)
{
return math.Div(x, y);
}
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
public static void Main(string[] args)
{
// Create ProxyMath NOT RealMath(Don't Touch RealMath)

ProxyMath proxy = new ProxyMath();

// Do the math :)

Console.WriteLine("4 + 2 = " + proxy.Add(4, 2));

// We don't have acces to this function, so we can't write that:
//Console.WriteLine("4 - 2 = " + proxy.Sub(4, 2));

Console.WriteLine("4 * 2 = " + proxy.Mul(4, 2));
Console.WriteLine("4 / 2 = " + proxy.Div(4, 2));

// Wait for user

Console.ReadKey();
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **

FACTORY METHOD

Is a Creational Design Pattern that allows us to create objects without specifying the exact class that will be instantiated and returned. Instead of creating objects directly, we use a factory method to create and return them.

Factory Method Design Pattern is particularly useful when we don’t know the exact class of object that will be created at runtime.

// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
interface Kid
{

}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
class Boy : Kid
{
}

class Girl : Kid
{
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
abstract class Birth
{
public abstract Kid FactoryMethod(string type);
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
class ConcreteBirth : Birth
{
public override Kid FactoryMethod(string type)
{
switch (type)
{
case "boy": return new Boy();
case "girl": return new Girl();
default: throw new ArgumentException("Invalid type", "type");
}
}
}
// * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **

--

--