Junior
What design patterns exist in programming?
sobes.tech AI
Answer from AI
Design patterns are divided into three main categories: creational, structural, and behavioral.
Creational Patterns:
- Factory Method: Provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created.
// Product interface public interface IProduct { void DoSomething(); } // Concrete Product A public class ConcreteProductA : IProduct { public void DoSomething() { // Implementation } } // Concrete Product B public class ConcreteProductB : IProduct { public void DoSomething() { // Implementation } } // Abstract creator public abstract class Creator { // Factory method public abstract IProduct CreateProduct(); public void AnOperation() { var product = CreateProduct(); product.DoSomething(); } } // Concrete creator A public class ConcreteCreatorA : Creator { public override IProduct CreateProduct() { return new ConcreteProductA(); } } // Concrete creator B public class ConcreteCreatorB : Creator { public override IProduct CreateProduct() { return new ConcreteProductB(); } } - Abstract Factory: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
- Builder: Separates the construction of a complex object from its representation so that the same construction process can create different representations.
// Product public class Car { public string Engine { get; set; } public string Wheels { get; set; } public string Body { get; set; } public void Display() { // Show car details } } // Builder interface public interface ICarBuilder { void BuildEngine(); void BuildWheels(); void BuildBody(); Car GetCar(); } // Concrete builder public class SportsCarBuilder : ICarBuilder { private Car car = new Car(); public void BuildEngine() { car.Engine = "Sports Engine"; } public void BuildWheels() { car.Wheels = "Sports Wheels"; } public void BuildBody() { car.Body = "Sports Body"; } public Car GetCar() { return car; } } // Director public class CarDirector { public void Construct(ICarBuilder builder) { builder.BuildEngine(); builder.BuildWheels(); builder.BuildBody(); } } - Prototype: Specifies the kinds of objects to create using a prototypical instance and creates new objects by copying this prototype.
- Singleton: Ensures a class has only one instance and provides a global point of access to it.
Structural Patterns:
- Adapter: Converts the interface of a class into another interface clients expect. Adapter lets classes with incompatible interfaces work together.
// Incompatible class (adaptee) public class Adaptee { public void SpecificRequest() { // Implementation of specific request } } // Target interface public interface ITarget { void Request(); } // Adapter public class Adapter : ITarget { private readonly Adaptee _adaptee = new Adaptee(); public void Request() { _adaptee.SpecificRequest(); } } - Bridge: Decouples an abstraction from its implementation so that the two can vary independently.
- Composite: Composes objects into tree structures to represent hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
- Decorator: Attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
- Facade: Provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
// Subsystem part 1 public class SubsystemA { public void OperationA() { // ... } } // Subsystem part 2 public class SubsystemB { public void OperationB() { // ... } } // Facade public class Facade { private readonly SubsystemA subsystemA = new SubsystemA(); private readonly SubsystemB subsystemB = new SubsystemB(); public void SimplifiedOperation() { subsystemA.OperationA(); subsystemB.OperationB(); } } - Flyweight: Uses sharing to support large numbers of fine-grained objects efficiently.
- Proxy: Provides a surrogate or placeholder for another object to control access to it.
Behavioral Patterns:
- Chain of Responsibility: Avoids coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
public abstract class Handler { protected Handler _nextHandler; public void SetNext(Handler handler) { _nextHandler = handler; } public abstract void HandleRequest(int request); } public class ConcreteHandler1 : Handler { public override void HandleRequest(int request) { if (request >= 0 && request < 10) { // Handle request } else if (_nextHandler != null) { _nextHandler.HandleRequest(request); } } } public class ConcreteHandler2 : Handler { public override void HandleRequest(int request) { if (request >= 10 && request < 20) { // Handle request } else if (_nextHandler != null) { _nextHandler.HandleRequest(request); } } } - Command: Encapsulates a request as an object, thereby allowing for parameterization of clients with different requests, queuing of requests, and logging of operations.
- Iterator: Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
- Mediator: Defines an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
- Memento: Without violating encapsulation, captures and externalizes an object's internal state so that the object can be restored to this state later.
- Observer: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
public interface IObserver { void Update(string message); } public class Subject { private List<IObserver> _observers = new List<IObserver>(); public void Attach(IObserver observer) { _observers.Add(observer); } public void Detach(IObserver observer) { _observers.Remove(observer); } public void Notify(string message) { foreach (var observer in _observers) { observer.Update(message); } } public void SomeBusinessLogic() { // ... Notify("State changed"); // ... } } public class ConcreteObserver : IObserver { public void Update(string message) { // Handle notification } } - State: Allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
- Strategy: Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
- Template Method: Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing its structure.
- Visitor: Represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
// Visitor interface public interface IVisitor { void Visit(ElementA element); void Visit(ElementB element); } // Element interface public interface IElement { void Accept(IVisitor visitor); } // Concrete element A public class ElementA : IElement { public void Accept(IVisitor visitor) { visitor.Visit(this); } public string OperationA() { return "ElementA"; } } // Concrete element B public class ElementB : IElement { public void Accept(IVisitor visitor) { visitor.Visit(this); } public string OperationB() { return "ElementB"; } } // Concrete visitor public class ConcreteVisitor1 : IVisitor { public void Visit(ElementA element) { // Action for ElementA } public void Visit(ElementB element) { // Action for ElementB } }