Adapter model and decorator model

Theory is a powerful tool to guide practice

Adapter mode

Concept: adapt the interface of a class to what users expect. An adaptation allows classes that cannot work together, usually because their interfaces are not compatible, to work together by wrapping their own interfaces in an existing class.
Role:
·Target: the target can be a concrete abstract class or an interface
·Adapter role: its own business interface or implementation
·Adapter: transform the target's interface and its own business interface into the class you need

Demo
We have a business interface class, ReaderData, whose function is to read data, but the format of reading data needs to be implemented separately.
Our target data has two formats: binary and hexadecimal
We have implemented the interface class DataReaderBinary to read binary data.
The interface class for reading hexadecimal data DataReaderHexadecimal requires our own access

Interface class for reading data ReaderData

public interface ReaderData {

   String reader();
   
}

Implementation class of ReaderData

public class ReaderDataImpl implements ReaderData {

   public String reader() {
       return "Format that can read data: ";
   }
}

Interface class of binary data DataReaderBinary

public interface DataReaderBinary {
   //How to read binary data
   String reader();
}

Implementation class of binary data interface class

public class DataReaderBinaryImpl implements DataReaderBinary {

   private ReaderData readerData;
// Let this class get the ability to get data  
   public DataReaderBinaryImpl(ReaderData readerData) {
       this.readerData = readerData;
   }

   public String reader() {
       return readerData.reader()+" binary data";
   }
}

Hexadecimal data interface class DataReaderHexadecimal

public interface DataReaderHexadecimal {

    //How to read hex
    String reader();
}
  • Here, datareader hexadecimal is the functional interface we want to access, which is the target role
  • Our binary implementation class has the ability to read binary data. It is an adapter.
  • Now we're going to use adapters to give the adapter the capabilities of the target role.

The adapter is divided into two modes

  • Object Adapter Pattern
  • Class adapter pattern

The feature of object adapter is that it contains a target role, that is, target role object

public  class AdaptiveClass  implements DataReaderHexadecimal {

    private DataReaderBinary dataReaderBinary;

    public AdaptiveClass(DataReaderBinary  dataReaderBinary) {

        this.dataReaderBinary =dataReaderBinary;
    }

    public String readerHexadecimal() {
        return "Hexadecimal data";
    }
}

test

public class Test {

    public static void main(String[] args) {
        ReaderData readerData =new ReaderDataImpl();
        DataReaderBinary dataReaderBinary = new DataReaderBinaryImpl(readerData);
        AdaptiveClass adaptiveClass = new AdaptiveClass(dataReaderBinary);
        System.out.println(dataReaderBinary.reader()+" "+adaptiveClass.readerHexadecimal());
    }

test result

  • In this way, the binary interface class (i.e. any implementation under the adapter interface) can be adapted to the target role

Class adapter pattern

public  class AdaptiveClass extends DataReaderBinaryImpl implements DataReaderHexadecimal {

    public AdaptiveClass(ReaderData readerData) {
        super(readerData);
    }

    public String readerHexadecimal() {
        return "Hexadecimal data";
    }
}

test result

public class Test {

    public static void main(String[] args) {
        ReaderData readerData =new ReaderDataImpl();

        DataReaderBinary dataReaderBinary = new DataReaderBinaryImpl(readerData);

        AdaptiveClass adaptiveClass = new AdaptiveClass(readerData);
        String reader = dataReaderBinary.reader() +"  "+ adaptiveClass.readerHexadecimal();
        System.out.println(reader);
    }
}

And this way is that the implementation flexibility of the selected adapter is not good

Let's take a look at how IO in java uses the adapter pattern

  • InputStreamReader inherits from Reader and Reader implements Readable Closeable
  • How does he associate InputStream with the functions under InputStreamReader
  • In the source code, we can see that he passed in InputStream as a parameter
  • Here read is the adapter, and InputStream is the target object InputStreamReader is like an adapter
  • Similarly, the relationship between the inherited write and OutputStream of OutputStream writer is the same

Decorator

Concept: enhance the method on the original basis

  • Role:
  • Abstract component role: gives an abstract interface to standardize the object ready to receive additional responsibilities.
  • Concrete component role: defines a class that will receive additional responsibilities.
  • Decorator role: it's like an enhancer, using his enhancement method.
  • Concrete decorator role: generally, it inherits the enhancer to implement specific enhancement logic.

Demo
Abstract component role class
Saucer plate

/**
 * A plate
 */
public abstract class Saucer {
    /**
     * shape
     */
    protected abstract String shape();

    /**
     * Appearance
     */
    protected abstract String facade();
}

The implementation of specific component disk subclass

public class ASaucer extends Saucer {
    protected String shape() {
        return "square";
    }

    protected String facade() {
        return "Black stripe";
    }
}

Decorative role

public class SaucerDecorator extends Saucer {

    private Saucer saucer;

    public SaucerDecorator(Saucer saucer) {
        this.saucer = saucer;
    }

    protected String shape() {
        return saucer.shape();
    }

    protected String facade() {
        return saucer.facade();
    }
}

Specific decorative role

public class SaucerBlue extends SaucerDecorator {

    private Saucer saucer;

    public SaucerBlue(Saucer saucer) {
        super(saucer);
    }

    @Override
    protected String shape() {
        return super.shape()+"It can also turn into a circle";
    }

    @Override
    protected String facade() {
        return super.facade()+"And blue stripes";
    }
}

Test class

public class Test  {
    public static void main(String[] args) {
        Saucer saucer ;
        saucer = new ASaucer();
        saucer = new SaucerBlue(saucer);
        System.out.println(saucer.shape());
        System.out.println(saucer.facade());
    }
}

Let's take a look at some uses of decorator pattern in java
BufferedReader under IO package

Reader is an abstract class


BufferedReader inherits Reader and combines Reader into class


Let's take a look at his constructor

It also takes Reader as its own parameter, and constructs BufferedReader by using Reader
Here the Reader is the abstract component role and the BufferedReader is the decoration role

  • There are BufferedInputStream like this, which is inherited from * * FilterInputStream**
  • While FilterInputStream inherits from InputStream, they all put InputStream as a parameter into the constructor.
  • Among them, InputStream is an abstract class, which is the abstract component role, FilterInputStream is the decoration role, and BufferedInputStream is the concrete decoration role.
  • There are many specific decorators like BufferedInputStream under FilterInputStream, such as lineinputstream and datainputstream.
  • Reflection in spring

The difference between adapter mode and decorator mode

  • Adapter mode
    It is to integrate external interface functions into its own business.
  • Decorator mode
    It is the enhancement of the method function, adding more functions on the original basis.

Insert picture description here

Published 9 original articles, won praise 2, visited 2066
Private letter follow

Keywords: Java Spring

Added by hungryOrb on Mon, 03 Feb 2020 15:48:04 +0200