Real-life Example: Managing a configuration settings object for an application. There should only be one instance of the configuration settings to avoid inconsistencies.
Explanation: Ensures a class has only one instance and provides a global point of access to it.
Real-life Example: Notification systems. When an event (like an email received) occurs, all the subscribers (such as different modules of an application) are notified and updated automatically.
Explanation: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
usingSystem;usingSystem.Collections.Generic;// Subject InterfacepublicinterfaceIEmailSubject{voidRegisterObserver(IEmailObserver observer);voidRemoveObserver(IEmailObserver observer);voidNotifyObservers();}// Observer InterfacepublicinterfaceIEmailObserver{voidUpdate(string message);}// Concrete SubjectpublicclassEmailServer:IEmailSubject{privateList<IEmailObserver> observers;privatestring emailMessage;publicEmailServer() { observers =newList<IEmailObserver>(); }publicstring EmailMessage {get { return emailMessage; }set { emailMessage = value;NotifyObservers(); } }publicvoidRegisterObserver(IEmailObserver observer) {observers.Add(observer); }publicvoidRemoveObserver(IEmailObserver observer) {observers.Remove(observer); }publicvoidNotifyObservers() {foreach (var observer in observers) {observer.Update(emailMessage); } }}// Concrete ObserverspublicclassMobileApp:IEmailObserver{publicvoidUpdate(string message) {Console.WriteLine("Mobile App Notification: "+ message); }}publicclassDesktopApp:IEmailObserver{publicvoidUpdate(string message) {Console.WriteLine("Desktop App Notification: "+ message); }}publicclassWebApp:IEmailObserver{publicvoidUpdate(string message) {Console.WriteLine("Web App Notification: "+ message); }}// ProgramclassProgram{staticvoidMain() { // Create a subjectEmailServer emailServer =newEmailServer(); // Create observersIEmailObserver mobileApp =newMobileApp();IEmailObserver desktopApp =newDesktopApp();IEmailObserver webApp =newWebApp(); // Register observersemailServer.RegisterObserver(mobileApp);emailServer.RegisterObserver(desktopApp);emailServer.RegisterObserver(webApp); // Change the state of the subjectemailServer.EmailMessage="New Email: 'Observer Design Pattern in C#'"; // Remove an observeremailServer.RemoveObserver(desktopApp); // Change the state of the subject againemailServer.EmailMessage="New Email: 'Advanced C# Programming'"; }}
Factory Pattern:
Real-life Example: Creating objects in a banking application for different types of accounts (e.g., savings, checking). The factory method can return different types of accounts based on the input provided.
Explanation: Defines an interface for creating an object, but lets subclasses alter the type of objects that will be created.
Real-life Example: Adding functionality to a user interface component in a graphical application. For instance, adding scrollbars to a window.
Explanation: Allows behavior to be added to individual objects, dynamically, without affecting the behavior of other objects from the same class.
Strategy Pattern:
Real-life Example: Different algorithms for sorting data (e.g., quicksort, mergesort, bubblesort). The strategy pattern allows the selection of the algorithm at runtime.
Explanation: Defines a family of algorithms, encapsulates each one, and makes them interchangeable. This pattern lets the algorithm vary independently from clients that use it.
Real-life Example: Implementing undo functionality in a text editor. Each action (like typing or deleting) is encapsulated as an object that can be stored and executed.
Explanation: Encapsulates a request as an object, thereby allowing for parameterization of clients with queues, requests, and operations.
Adapter Pattern:
Real-life Example: Integrating with a third-party library where the interface does not match the rest of your application. An adapter can translate calls from your application to the third-party library. Payment gateway third party
Explanation: Allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code.
usingSystem;namespaceAdapterPattern{ // Target InterfacepublicinterfaceIPaymentGateway {voidProcessPayment(string cardNumber,string cardHolderName,DateTime expiryDate,decimal amount); } // Adaptee: Third-party payment gatewaypublicclassThirdPartyPaymentGateway {publicvoidPay(string cardNumber,string cardHolder,string expiry,decimal amount) {Console.WriteLine($"Payment of {amount:C} processed by ThirdPartyPaymentGateway for card {cardNumber}."); } } // Adapter: Adapts ThirdPartyPaymentGateway to IPaymentGatewaypublicclassPaymentGatewayAdapter:IPaymentGateway {privatereadonlyThirdPartyPaymentGateway _thirdPartyPaymentGateway;publicPaymentGatewayAdapter(ThirdPartyPaymentGateway thirdPartyPaymentGateway) { _thirdPartyPaymentGateway = thirdPartyPaymentGateway; }publicvoidProcessPayment(string cardNumber,string cardHolderName,DateTime expiryDate,decimal amount) { // Convert expiryDate to string format expected by the third-party gatewaystring expiry =expiryDate.ToString("MM/yy");_thirdPartyPaymentGateway.Pay(cardNumber, cardHolderName, expiry, amount); } } // Client codeclassProgram {staticvoidMain(string[] args) { // Create an instance of the third-party payment gatewayThirdPartyPaymentGateway thirdPartyPaymentGateway =newThirdPartyPaymentGateway(); // Create an instance of the adapterIPaymentGateway paymentGateway =newPaymentGatewayAdapter(thirdPartyPaymentGateway); // Use the payment gateway via the adapterpaymentGateway.ProcessPayment("1234-5678-9012-3456","John Doe",newDateTime(2025,12,31),100.00m); // Output: Payment of $100.00 processed by ThirdPartyPaymentGateway for card 1234-5678-9012-3456. } }}
Prototype Pattern:
Real-life Example: Creating objects in a graphic application (e.g., shapes, drawings). Instead of creating new instances from scratch, a prototype pattern clones existing objects.
Explanation: Specifies the kind of objects to create using a prototypical instance, and creates new objects by copying this prototype.
Builder Pattern:
Real-life Example: Constructing complex objects such as vehicles, where different parts like engine, wheels, and body can be configured step-by-step.
Explanation: Separates the construction of a complex object from its representation so that the same construction process can create different representations.
Facade Pattern:
Real-life Example: Simplifying interactions with a complex library or framework (e.g., a library for 3D graphics). A facade provides a simplified interface to the complex subsystems. Banking system
Explanation: Provides a unified interface to a set of interfaces in a subsystem, making the subsystem easier to use.
usingSystem;namespaceFacadePattern{ // Subsystem Class 1publicclassAccountService {publicvoidGetAccountDetails(string accountId) {Console.WriteLine($"Fetching account details for account ID: {accountId}"); } } // Subsystem Class 2publicclassTransferService {publicvoidTransferAmount(string fromAccount,string toAccount,decimal amount) {Console.WriteLine($"Transferring {amount:C} from {fromAccount} to {toAccount}"); } } // Subsystem Class 3publicclassLoanService {publicvoidApplyForLoan(string accountId,decimal loanAmount) {Console.WriteLine($"Applying for a loan of {loanAmount:C} for account ID: {accountId}"); } } // Facade ClasspublicclassBankingFacade {privatereadonlyAccountService _accountService;privatereadonlyTransferService _transferService;privatereadonlyLoanService _loanService;publicBankingFacade() { _accountService =newAccountService(); _transferService =newTransferService(); _loanService =newLoanService(); }publicvoidGetAccountDetails(string accountId) {_accountService.GetAccountDetails(accountId); }publicvoidTransferAmount(string fromAccount,string toAccount,decimal amount) {_transferService.TransferAmount(fromAccount, toAccount, amount); }publicvoidApplyForLoan(string accountId,decimal loanAmount) {_loanService.ApplyForLoan(accountId, loanAmount); } } // Client codeclassProgram {staticvoidMain(string[] args) {BankingFacade bankingFacade =newBankingFacade(); // Use the facade to perform various operationsbankingFacade.GetAccountDetails("12345");bankingFacade.TransferAmount("12345","67890",500.00m);bankingFacade.ApplyForLoan("12345",10000.00m); } }}
Proxy Pattern:
Real-life Example: Accessing a remote service or resource. A proxy can control access to the original object, allowing additional functionalities like lazy initialization, logging, or access control.
Explanation: Provides a surrogate or placeholder for another object to control access to it.
Chain of Responsibility Pattern:
Real-life Example: Support Ticket Processing System. Imagine a support ticket system where a customer support request could be handled by multiple levels of support staff: Level 1, Level 2, and Level 3 support. Each level of support will try to handle the request, and if it cannot, it will pass the request to the next level.
Explanation: Passes a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain.
usingSystem;namespaceChainOfResponsibilityExample{ // Enum for issue severitypublicenumIssueSeverity { Low, Medium, High } // Support ticket classpublicclassSupportTicket {publicIssueSeverity IssueSeverity { get; set; }publicstring Description { get; set; }publicSupportTicket(IssueSeverity severity,string description) { IssueSeverity = severity; Description = description; } } // Abstract handlerpublicabstractclassSupportHandler {protectedSupportHandler _nextHandler;publicvoidSetNextHandler(SupportHandler nextHandler) { _nextHandler = nextHandler; }publicabstractvoidHandleRequest(SupportTicket ticket); } // Concrete handler for Level 1 supportpublicclassLevel1SupportHandler:SupportHandler {publicoverridevoidHandleRequest(SupportTicket ticket) {if (ticket.IssueSeverity==IssueSeverity.Low) {Console.WriteLine("Level 1 Support: Handling low severity issue."); }elseif (_nextHandler !=null) {_nextHandler.HandleRequest(ticket); } } } // Concrete handler for Level 2 supportpublicclassLevel2SupportHandler:SupportHandler {publicoverridevoidHandleRequest(SupportTicket ticket) {if (ticket.IssueSeverity==IssueSeverity.Medium) {Console.WriteLine("Level 2 Support: Handling medium severity issue."); }elseif (_nextHandler !=null) {_nextHandler.HandleRequest(ticket); } } } // Concrete handler for Level 3 supportpublicclassLevel3SupportHandler:SupportHandler {publicoverridevoidHandleRequest(SupportTicket ticket) {if (ticket.IssueSeverity==IssueSeverity.High) {Console.WriteLine("Level 3 Support: Handling high severity issue."); }else {Console.WriteLine("Issue could not be handled."); } } } // Main programclassProgram {staticvoidMain(string[] args) { // Create handlersvar level1 =newLevel1SupportHandler();var level2 =newLevel2SupportHandler();var level3 =newLevel3SupportHandler(); // Set up the chain of responsibilitylevel1.SetNextHandler(level2);level2.SetNextHandler(level3); // Create support ticketsvar ticket1 =newSupportTicket(IssueSeverity.Low,"Password reset");var ticket2 =newSupportTicket(IssueSeverity.Medium,"Unable to access account");var ticket3 =newSupportTicket(IssueSeverity.High,"System outage"); // Process the ticketslevel1.HandleRequest(ticket1);level1.HandleRequest(ticket2);level1.HandleRequest(ticket3); } }}
Composite Pattern:
Real-life Example: Representing a hierarchy of graphical objects, where individual objects (e.g., lines, circles) and groups of objects are treated uniformly.
Explanation: Composes objects into tree structures to represent part-whole hierarchies, allowing clients to treat individual objects and compositions uniformly.
Flyweight Pattern:
Real-life Example: Managing a large number of fine-grained objects efficiently, such as characters in a text editor. Flyweight minimizes memory usage by sharing as much data as possible.
Explanation: Uses sharing to support large numbers of fine-grained objects efficiently.
State Pattern:
Real-life Example: A vending machine that changes its behavior based on the current state (e.g., no coin inserted, coin inserted, dispensing product).
Explanation: Allows an object to alter its behavior when its internal state changes, making the object appear to change its class.
Memento Pattern:
Real-life Example: Implementing undo functionality in applications. A memento captures and stores the current state of an object so it can be restored later.
Explanation: Captures and externalizes an object's internal state so that it can be restored later without violating encapsulation.
Template Method Pattern:
Real-life Example: Defining the skeleton of an algorithm in a method in a base class, leaving the implementation of some steps to subclasses. For example, a base class providing a template for document generation with specific steps for different document formats.
Explanation: Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses.
Visitor Pattern:
Real-life Example: Performing operations on a collection of objects with different types (e.g., a compiler performing type checking, optimization, and code generation on an abstract syntax tree).
Explanation: Represents an operation to be performed on elements of an object structure, allowing new operations to be defined without changing the classes of the elements on which it operates.
Mediator Pattern:
Real-life Example: Managing interactions between multiple components in a user interface. Instead of each component interacting directly with every other component, a mediator handles the communication, reducing dependencies. Chat Room example
Explanation: Defines an object that encapsulates how a set of objects interact, promoting loose coupling by keeping objects from referring to each other explicitly.
usingSystem;usingSystem.Collections.Generic;// Mediator InterfacepublicinterfaceIChatRoomMediator{voidSendMessage(string message,User user);voidRegisterUser(User user);}// Concrete MediatorpublicclassChatRoom:IChatRoomMediator{privatereadonlyDictionary<string,User> _users =newDictionary<string,User>();publicvoidRegisterUser(User user) {if (!_users.ContainsKey(user.Name)) {_users[user.Name] = user; }user.SetChatRoom(this); }publicvoidSendMessage(string message,User user) {foreach (var u in_users.Values) { // Don't send the message to the senderif (u != user) {u.Receive(message,user.Name); } } }}// Colleague InterfacepublicabstractclassUser{protectedIChatRoomMediator _chatRoom;publicstring Name { get; privateset; }publicUser(string name) { Name = name; }publicvoidSetChatRoom(IChatRoomMediator chatRoom) { _chatRoom = chatRoom; }publicvoidSend(string message) {Console.WriteLine($"{Name} sends: {message}");_chatRoom.SendMessage(message,this); }publicabstractvoidReceive(string message,string from);}// Concrete ColleaguepublicclassChatUser:User{publicChatUser(string name) : base(name) { }publicoverridevoidReceive(string message,string from) {Console.WriteLine($"{Name} received from {from}: {message}"); }}// Client CodepublicclassProgram{publicstaticvoidMain(string[] args) {IChatRoomMediator chatRoom =newChatRoom();User user1 =newChatUser("Alice");User user2 =newChatUser("Bob");User user3 =newChatUser("Charlie");chatRoom.RegisterUser(user1);chatRoom.RegisterUser(user2);chatRoom.RegisterUser(user3);user1.Send("Hello, everyone!");user2.Send("Hi Alice!");user3.Send("Hey Alice and Bob!"); }}