Friday, December 29, 2023

Adapter Design Pattern in C#

The Adapter Design Pattern is a structural pattern that allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, enabling them to collaborate seamlessly without modifying their existing code.The adapter plays the role of converter or translator.

This pattern is particularly useful when integrating new components or systems that have different interfaces from the ones already in use.

To handle the incompatibility, we use different approaches, and based on that, we can classify the Adapter Pattern into 2 parts.

  • Object Adapter Pattern
  • Class Adapter Pattern

Object Adapter Design Pattern

In Object Adapter Pattern, Incompatibility is handled by creating the object.

Class Adapter Design Pattern

Class Adapter Design Pattern Incompatibility is handled by inheritance.

Components of Adapter Design Pattern

  • Target: The interface that is expected by the client code.
  • Adaptee: The existing class or interface that needs to be integrated into the system but has an incompatible interface with the Target.
  • Adapter: The class that bridges the gap between Target and Adaptee by implementing the Target interface and internally using the Adaptee.

Example in C#:

Let's consider a scenario where we have an OldPrinter class with a method PrintOld(), and we want to integrate it into a system that expects a different interface, say INewPrinter with PrintNew() method.In this example, the PrinterAdapter class implements the INewPrinter interface by internally using the OldPrinter class.

  1. Adaptee: Existing class with an incompatible interface.
        namespace AdapterPattern.Adaptee
    {
        public class OldPrinter
        {
            public void PrintOld()
            {
                Console.WriteLine("Printing with the old printer.");
            }
        }
    }
        
  2. Target: New interface expected by the client.
       namespace AdapterPattern.Target
    {
        public interface INewPrinter
        {
            void PrintNew();
        }
    }
        
  3. Adapter: Bridges the gap between OldPrinter and INewPrinter.
       using AdapterPattern.Adaptee;
    using AdapterPattern.Target;
    
    namespace AdapterPattern.Adapter
    {
        // Adapter: Bridges the gap between OldPrinter and INewPrinter
        public class PrinterAdapter : INewPrinter
        {
            private readonly OldPrinter oldPrinter;
    
            public PrinterAdapter(OldPrinter oldPrinter)
            {
                this.oldPrinter = oldPrinter;
            }
    
            public void PrintNew()
            {
                // Call the old printer's method through the adapter
                oldPrinter.PrintOld();
            }
        }
    }
        
  4. Client: The client code interacts with the INewPrinter interface, which internally calls the methods of the OldPrinter class through the adapter..
       using AdapterPattern.Adaptee;
    using AdapterPattern.Adapter;
    using AdapterPattern.Target;
    
    OldPrinter oldPrinter = new OldPrinter();
    
    // Adapter to use OldPrinter as a NewPrinter
    INewPrinter adaptedPrinter = new PrinterAdapter(oldPrinter);
    
    // Using the NewPrinter interface
    adaptedPrinter.PrintNew();
    Console.ReadLine();
        

Output

adapter design pattern example

Advantages of the Adapter Pattern:

  • Interoperability: Allows integration of incompatible interfaces.
  • Reusability: Existing classes can be used in new systems without modifying their code.
  • Maintainability: Helps in keeping existing code intact while adapting to new requirements.

The Adapter Design Pattern is a powerful tool for integrating diverse components or systems with different interfaces, promoting flexibility and maintainability in software design.

The full source code is available here:

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top