9/24/2026
5/29/2026
State Pattern
✅ Why we use the State Pattern (short)
- Avoids large
if/elseorswitchblocks based on state - Object behavior changes dynamically depending on its current state
- Follows clean design principles (Open/Closed, Single Responsibility)
- Makes code easier to maintain, extend, and test.
- Also validations can be done inside states ,and can prevent issues.
- Can also introduce new states, easily
✅ Key Idea
👉 Each state is a separate class
DraftState,ReviewState,PublishedState, etc.- Each class contains behavior specific to that state
- The main object (Context) just delegates work to the current state
🧠 One-line understanding
Instead of checking state with conditions, the object becomes the state by delegating to state classes.
5/20/2026
Adapter Pattern
Here is a clean, simple explanation with formatted code and key points added 👇
❌ Without Adapter
Old class:
class OldLogger
{
public void WriteLog(string message)
{
Console.WriteLine(message);
}
}
Client:
class NewApp
{
OldLogger logger = new OldLogger();
public void Process()
{
logger.WriteLog("Processing");
}
}
👉 Problem:
NewApp is directly dependent on OldLogger → tightly coupled → hard to replace or test
✅ With Adapter
Target interface:
interface ILogger
{
void Log(string message);
}
Old class (unchanged):
class OldLogger
{
public void WriteLog(string message)
{
Console.WriteLine(message);
}
}
Adapter:
class LoggerAdapter : ILogger
{
private OldLogger oldLogger;
public LoggerAdapter(OldLogger oldLogger)
{
this.oldLogger = oldLogger;
}
public void Log(string message)
{
oldLogger.WriteLog(message);
}
}
Client:
class NewApp
{
private ILogger logger;
public NewApp(ILogger logger)
{
this.logger = logger;
}
public void Process()
{
logger.Log("Processing");
}
}
Usage:
var app = new NewApp(new LoggerAdapter(new OldLogger()));
✅ Why we need Adapter
Used when an existing class cannot be changed but its method does not match what your system expects. Adapter converts one interface into another so both can work together.
✅ Use of Adapter
It helps integrate legacy code, third-party libraries, or different systems without modifying them. It keeps your main code clean because the client works only with an interface, not the actual old class.
✅ Final Idea
Without adapter → client depends on concrete class
With adapter → client depends on interface, adapter handles conversion
👉 Adapter hides incompatibility and reduces coupling in your main logic
Prototype Design Pattern
| Aspect | Without Prototype (new) | With Prototype (clone) |
|---|---|---|
| Creation | Build from scratch | Copy existing |
| Speed | ❌ Slow | ✅ Fast |
| CPU | ❌ High | ✅ Low |
| Memory | ✅ Same | ✅ Same |
| Use case | Simple objects | Complex/expensive objects |
| Risk | ✅ Safe | ⚠️ Copy issues |
🔁 Shallow vs Deep Copy
| Type | Description | Speed | Risk |
|---|---|---|---|
| Shallow | Copies references | ✅ Fast | ❌ Shared data |
| Deep | Full independent copy | ❌ Slower | ✅ Safe |
3/26/2026
Builder Pattern
Builder Pattern in C#
The Builder Pattern helps construct complex objects step-by-step. It is useful when you want to prevent creating incomplete or invalid objects. For example, just like a car should not be created without a steering wheel, your object should not be created without required fields.
Without Builder Pattern
When many parameters are required, constructors become difficult to maintain and easy to misuse.
public class User
{
public string Name { get; }
public int Age { get; }
public string Email { get; }
public string Address { get; }
public User(string name, int age, string email, string address)
{
Name = name;
Age = age;
Email = email;
Address = address;
}
}
// Hard to remember parameter order
var user = new User("Vinodh", 30, "v@example.com", "Bangalore");
With Builder Pattern (With Validation)
The Builder Pattern allows you to set values step-by-step and validate them before creating the final object.
public class User
{
public string Name { get; private set; }
public int Age { get; private set; }
public string Email { get; private set; }
public string Address { get; private set; }
private User() { }
public class Builder
{
private readonly User _user = new User();
public Builder SetName(string name)
{
_user.Name = name;
return this;
}
public Builder SetAge(int age)
{
_user.Age = age;
return this;
}
public Builder SetEmail(string email)
{
_user.Email = email;
return this;
}
public Builder SetAddress(string address)
{
_user.Address = address;
return this;
}
public User Build()
{
// Validation logic – prevents invalid object creation
if (string.IsNullOrWhiteSpace(_user.Name))
throw new Exception("Name is required.");
if (_user.Age <= 0)
throw new Exception("Age must be a positive value.");
if (string.IsNullOrWhiteSpace(_user.Email))
throw new Exception("Email is required.");
// Similar to: a car cannot be created without a steering wheel
if (string.IsNullOrWhiteSpace(_user.Address))
throw new Exception("Address cannot be empty.");
return _user;
}
}
}
Usage
var user = new User.Builder()
.SetName("Vinodh")
.SetAge(30)
.SetEmail("v@example.com")
.SetAddress("Bangalore")
.Build();
Conclusion
The Builder Pattern prevents invalid object creation through step-by-step construction and validation. Just like a car must not be built without vital parts, your objects remain consistent and safe.