Adapter design pattern of C# design pattern

Posted by DusterG20 on Tue, 01 Feb 2022 12:53:04 +0100

adapter design pattern

Model introduction

Design mode: structural design mode.

Adapter pattern is a structural design pattern with high frequency of use. If there are incompatible interfaces in the system, we can introduce an adapter class as an intermediate class to make two classes that cannot work together because of incompatible interfaces cooperate with each other.

Adapter design pattern class diagram:

Class adapter:

Object adapter:

The adapter mode is mainly composed of three objects:

Target (target abstract class):

The target abstract class defines the interface required by the customer, which can be either an abstract class or an interface or a concrete class. In the class adapter, since C# only supports single inheritance, the target abstract class can only be an interface.

Adapter class:

It can call another interface to adapt Adaptee and Target as a converter. Adapter adapter is the core class of adapter pattern. In class adapter, it makes the relationship between them by implementing Target interface and inheriting Adaptee. In object adapter, it makes the relationship between them by inheriting or implementing Target interface and associating Adaptee.

Adaptee (adapter class):

Adapter class is the object that needs to be adapted. It defines an existing interface and needs to be adapted. Generally, it is a specific class, which contains the business methods that the client wants to call.

code implementation

Class adapter implementation:

Target:

namespace Adapter.Adapter.Example.ClassAdapter
{
    public interface ITarget
    {
        void Operation();
    }
}

Adapter:

namespace Adapter.Adapter.Example.ClassAdapter
{
    public class ClassAdapter : ClassAdaptee,ITarget
    {
        public void OperationAdapter()
        {
            base.Operation();
        }
    }
}

Adaptee:

namespace Adapter.Adapter.Example.ClassAdapter
{
    public class ClassAdaptee
    {
        public void Operation()
        {
            
        }
    }
}

Object adapter implementation:

Target:

namespace Adapter.Adapter.Example.ClassAdapter
{
    public interface ITarget
    {
        void Operation();
    }
}

Adapter:

namespace Adapter.Adapter.Example.ClassAdapter
{
    public class Adapter : ITarget
    {
        private Adaptee _adaptee;

        public void SetAdaptee(Adaptee adaptee)
        {
            _adaptee = adaptee;
        }

        public void Operation()
        {
            _adaptee.Operation();
            
        }
    }
}

Adaptee:

namespace Adapter.Adapter.Example.ClassAdapter
{
    public class Adaptee
    {
        public void Operation()
        {
            
        }
    }
}

Default adapter implementation:

The default adapter means that sometimes we may not need to use all the methods in the target interface. At this time, we need to encapsulate a layer of abstract adapter to implement the empty method, and then the subclass of the abstract adapter decides to override that method for use.

Target:

namespace Adapter.Adapter.Example.DefaultAdapter
{
    public interface ITarget
    {
        void Operation1();
        void Operation2();
        void Operation3();
    }
}

AbstractAdapter:

namespace Adapter.Adapter.Example.DefaultAdapter
{
    public abstract class AbstractAdapter : ITarget
    {
        public void Operation1()
        {
            
        }

        public void Operation2()
        {
            
        }

        public void Operation3()
        {
            
        }
    }
}

ConcreteAdapter:

namespace Adapter.Adapter.Example.DefaultAdapter
{
    public class ConcreteAdapter : AbstractAdapter
    {
        private Adaptee _adaptee;

        public void SetAdaptee(Adaptee adaptee)
        {
            _adaptee = adaptee;
        }
        public new void Operation1()
        {
            _adaptee.Operation1();
        }
    }
}

Adaptee:

namespace Adapter.Adapter.Example.DefaultAdapter
{
    public class Adaptee
    {
        public void Operation1()
        {
            
        }
    }
}

Bidirectional adapter implementation:

The and core of the bidirectional adapter lies in the previous target abstract class and adapter class, which are both target abstract class and adapter class here.

Target:

namespace Adapter.Adapter.Example.DoubleAdapter
{
    public interface ITarget
    {
        void TargetOperation();
    }
}

ConcreteTarget:

namespace Adapter.Adapter.Example.DoubleAdapter
{
    public class ConcreteTarget : ITarget
    {
        public void TargetOperation()
        {
            
        }
    }
}

Adapter:

namespace Adapter.Adapter.Example.DoubleAdapter
{
    public class Adapter : ITarget, IAdaptee
    {
        private ITarget _target;
        private IAdaptee _adaptee;

        public void SetTarget(ITarget target)
        {
            _target = target;
        }

        public void SetAdaptee(IAdaptee adaptee)
        {
            _adaptee = adaptee;
        }
        public void TargetOperation()
        {
            _target.TargetOperation();
        }

        public void AdapteeOperation()
        {
            _adaptee.AdapteeOperation();
        }
    }
}

Adaptee:

namespace Adapter.Adapter.Example.DoubleAdapter
{
    public interface IAdaptee
    {
        void AdapteeOperation();
    }
}

ConcreteAdaptee:

namespace Adapter.Adapter.Example.DoubleAdapter
{
    public class ConcreteAdaptee : IAdaptee
    {
        public void AdapteeOperation()
        {
            
        }
    }
}

Adapter mode summary

Advantages of adapter mode

  1. Decouple the target class from the adapter class, and reuse the existing adapter class by introducing an adapter class without modifying the original structure.
  2. Increase the transparency and reusability of the class, and encapsulate the specific business implementation process in the adapter class. It is transparent to the client. An adapter can be used in multiple systems to improve the reusability.

Disadvantages of adapter mode

  1. For class adapters, such as C#, JAVA, which only supports single inheritance, there can only be one adapter class at a time, and it is impossible to adapt multiple adapters at the same time.
  2. For the class adapter, the adapter cannot be the final class, and C# cannot be the sealed class.
  3. For class adapters, in C#, JAVA only supports single inheritance, so the target abstract class must be an interface.
  4. For the object adapter pattern, compared with the class adaptation pattern, some methods to replace the adapter class in the adapter are more troublesome.

Usage environment of adapter mode

  1. The system needs to use some existing classes, and the interfaces of these classes do not meet the system requirements, and there is even no source code of these classes. Here, the adapter will be compatible with the needs of both sides.
  2. It is hoped that some unrelated classes can work together. Here, the adapter will play the role of function combination.

Topics: C# Design Pattern