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