tylkonachwile
tylkonachwile

Reputation: 2257

Adapter pattern in C#

I'm wondering whether I understand this pattern correctly. Let's assume that we have interface incompatibility. Function Printer() from 3rd party dll, requires IHPPrinter, but our object does not implement this interfece... So finally we have got to implement this interface and return our implementation of method, like in code below? :) The second question is, if we don't provide implementation for method DocumentsInQueue, exeception will be thrown. Is some possibility to prevent calling this method?

class Program
{
    static void Main(string[] args)
    {
        EpsonPrinter _epsonPrinter = new EpsonPrinter();
        Printer(_epsonPrinter);
        Console.ReadKey();
    }


    public static void Printer(IHPPrinter hpPrinter)
    {
        hpPrinter.PrintDocument();
    }

    public interface IHPPrinter
    {
        void PrintDocument();
        int DocumentsInQueue();
    }
    public interface IEpsonPrinter
    {
        void Print();
    }

    public class EpsonPrinter : IEpsonPrinter, IHPPrinter
    {
        public int DocumentsInQueue()
        {
            throw new NotImplementedException();
        }

        public void Print()
        {
            this.PrintDocument();
        }

        public void PrintDocument()
        {
            Console.WriteLine("Printing from Epson printer...");
        }


    }
}

Upvotes: 0

Views: 1088

Answers (1)

Bradley Uffner
Bradley Uffner

Reputation: 16991

The code you provided is not an example of the Adapter Pattern.

An adapter for your example would be its own class, probably something like EpsonPrinterToHpPrinterAdapter. It would implement IHPPrinter and take an instance of an IEpsonPrinter implementation as an argument to its constructor.

You would then pass an instance of EpsonPrinterToHpPrinterAdapter to the method that expects IHPPrinter. The adapter class would then translate all calls from IHPPrinter methods to calls to the reference of the IEpsonPrinter from the constructor.

Thr primary goal of the Adapter pattern is to have a class to makes class B act like class A by translating, as best as possible the behavior from one to the other. You can't prevent a member from being called, you have to provide some kind of special implementation of it that will work for the class you are adapting.

In your specific example, it would be fairly trivial to pass the call of PrintDocument to Print directly, but the call to DocumentsInQueue is more difficult, since there is no matching member on IEpsonPrinter. You might have to track and return the count separately, incrementing an internal counter every time PrintDocument is called, and decrementing it when it finishes.

This type of pattern becomes very important when you don't controll all parts of those code. If the EpsonPrinter and the Printer classes were both defined in 3rd party libraries that you can't modify, you would use this pattern to connect them together.

I've taken your example and made the changes needed to use an Adapter pattern:

class Program
    {
        static void Main(string[] args)
        {
            EpsonPrinter epsonPrinter = new EpsonPrinter();
            EpsonPrinterToHPPrinterAdapter adapter = new EpsonPrinterToHPPrinterAdapter(epsonPrinter);
            Printer(adapter);
            Console.ReadKey();
        }


        public static void Printer(IHPPrinter hpPrinter)
        {
            hpPrinter.PrintDocument();
        }

        public interface IHPPrinter
        {
            void PrintDocument();
            int DocumentsInQueue();
        }
        public interface IEpsonPrinter
        {
            void Print();
        }

        public class EpsonPrinterToHPPrinterAdapter :  IHPPrinter
        {

            public EpsonPrinterToHPPrinterAdapter(IEpsonPrinter epsonPrinter)
            {
                EpsonPrinter = epsonPrinter;
                _queueCount = 0;
            }

            private int _queueCount;

            public IEpsonPrinter EpsonPrinter { get; }

            public void PrintDocument()
            {
                _queueCount++;
                EpsonPrinter.Print();
                _queueCount--;
            }

            public int DocumentsInQueue()
            {
                return _queueCount;
            }
        }

        public class EpsonPrinter : IEpsonPrinter
        {
            public void Print()
            {
                Console.WriteLine("Printing from Epson printer...");
            }
        }
    }

Upvotes: 2

Related Questions