Design patterns to enjoy with frequently used Java libraries --Adapter patterns

GoF design patterns are also hidden in the Java libraries that you use most often. It's easy to overlook the busy daily work, but once in a while, let's enjoy the beautiful design, which can be said to be a kind of art.

This art

source file

Common


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...

Logger logger = LoggerFactory.getLogger(this.getClass());
...

Jar file to add to classpath [^ 1]

Pattern 1-When using Logback


- slf4j-api-VERSION.jar
- logback-classic-VERSION.jar
- logback-core-VERSION.jar

Pattern 2-When using Log4j


- slf4j-api-VERSION.jar
- slf4j-log4j12-VERSION.jar
- log4j-VERSION.jar

Pattern 3-When using Java standard logger


- slf4j-api-VERSION.jar
- slf4j-jdk14-VERSION.jar
- rt.jar (Because it is a core Java library, it is from the beginning)

This is a scene to generate a Java logger (SLF4J). You can freely choose the logger implementation by simply replacing the jar file added to the classpath while keeping the source code. I feel the artistry that the interface and the implementation are separated very neatly.

Points of appreciation

Since there are various Java logging libraries [^ 2], I think that you often use different ones for each project. When trying to use the source of another project in my own project, if the logger used is different, I have to modify the source code or manage the logger's configuration file twice. It will not be beautiful.

The point of appreciation this time is that by preparing an adapter class, you can use it in the same way even if you replace the implementation class (logger). What's more, the implementation class replacement is the classic but simplest method of simply replacing the jar. We are in awe of the designer's chic design for us who use the library, as well as the beauty of the design. Let's watch it together below.

When not using the Adapter pattern

If you write the code at the beginning without using the Adapter pattern, it will be as follows.

Pattern 1-When using Logback


import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.Logger;
...

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger log = lc.getLogger(this.getClass());

Pattern 2-When using Log4j


import org.apache.log4j.Logger;
...

Logger logger = Logger.getLogger(this.getClass());

Pattern 3-When using Java standard logger


import java.util.logging.Logger;
...

Logger logger = Logger.getLogger(this.getClass());

The description at the time of instance acquisition and the description of the import statement are different for each logger. Also, since the Logger class to be instantiated is different, the methods that can be used for each are also different. If you change the logging library in this state, you will end up replacing a lot of source code. Moreover, if you were using a method that only exists in a particular logging library, you can't even replace it.

When using the Adapter pattern

The code at the beginning uses the Adapter pattern. Let's look again.

First is the jar file to add to the classpath. Every logging library has three jar files, but they have the same role,

It has become.

The table below shows the types of logging libraries and the roles of jars.

Logback Log4j Java standard logger
Common IF slf4j-api-VERSION.jar Same on the left Same on the left
IF implementation (adapter) logback-classic-VERSION.jar slf4j-log4j12-VERSION.jar slf4j-jdk14-VERSION.jar
Logging library implementation logback-core-VERSION.jar log4j-VERSION.jar rt.jar

Then, regardless of which logging library you are using, the logger instance will be uniformly generated as follows.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...

Logger logger = LoggerFactory.getLogger(this.getClass());
...

The contents of this getLogger method are as follows.

java:org.slf4j.LoggerFactory.java


package org.slf4j;
...

//Classes in the common IF jar
public final class LoggerFactory {
    ...
    public static Logger getLogger(String name) {

        // org.slf4j.Create an instance of ILoggerFactory
        //The implementation class is the class in the IF implementation (adapter) jar (see table below)
        ILoggerFactory iLoggerFactory = getILoggerFactory();

        // org.slf4j.Create an instance of Logger
        //The implementation class is the class in the IF implementation (adapter) jar (see table below)
        return iLoggerFactory.getLogger(name);
    }
    ...
}

The implementation classes of ʻILoggerFactory and Logger` are as follows. Both classes are included in the IF implementation (adapter) jar of their logging library.

Logback Log4j Java standard logger
Implementation class of ILoggerFactory ch.qos.logback.classic.LoggerContext org.slf4j.impl.Log4jLoggerFactory org.slf4j.jul.JDK14LoggerFactory
org.slf4j.Logger implementation class ch.qos.logback.classic.Logger org.slf4j.impl.Log4jLoggerAdapter org.slf4j.jul.JDK14LoggerAdapter

If you follow this source code, you can see that the instances of LoggerFactory and Logger are created in the following flow. Which jar each class is included in is written in []. It is easy to understand if you are aware of it.

For Logback


org.slf4j.LoggerFactory [common IF jar]
     ↓
     ↓ org/slf4j/impl/StaticLoggerBinder.class file
↓ Find and instantiate
     ↓
org.slf4j.impl.StaticLoggerBinder [IF implementation (adapter) jar]
     ↓
     ↓ org.slf4j.ILoggerFactory interface
Instantiate LoggerContext that implements ↓
     ↓
ch.qos.logback.classic.LoggerContext [IF implementation (adapter) jar]
     ↓
     ↓ org.slf4j.Logger interface
Ch that implements ↓.qos.logback.classic.Instantiate Logger
     ↓
ch.qos.logback.classic.Logger [IF implementation (adapter) jar]

The point is that the finally generated Logger is not a class included in the logging library implementation jar, but a class included in the IF implementation jar. This class holds a reference to the logging library in a member variable and calls it when logging.

By doing the above, the person who uses SLF4J will not refer directly to the instance of the logging library, but will refer to the IF implementation class corresponding to the adapter.

For Logback


People who use SLF4J
 ↓
↓ Use
 ↓
org.slf4j.Logger [common IF jar]
This entity is ch.qos.logback.classic.Logger [IF implementation (adapter) jar]
   ↓
↓ Used internally
   ↓
  ch.qos.logback.core.XXXAppender [logging library implementation jar]

Summary of Adapter pattern

The Adapter pattern is sometimes referred to as the Wrapper pattern. ** Wrap in a new class to make it easier to use a class that is difficult to use as it is **. By the way, a class that is difficult to use as it is is a class in which the methods are not unified among similar classes or the source code is dirty.

No wonder the SLF4J interface should be clean. It's the result of being formatted with the Adapter pattern for the purpose of cleaning up.

For this example, I chose the one that maximizes the attractiveness of the Adapter pattern, but even if I do not do it thoroughly (IF, IF implementation, logging library implementation, I do not have to separate the jar files) ), ** Just create a wrapper class for a class that is difficult to use as it is, and you are using the Adapter pattern **.

Expert comments on the Adapter pattern

Many experts have also commented on evaluating the Adapter pattern.

Hiroshi Yuki

Even in the world of programming, when what is already provided cannot be used as it is, it is often converted to the required form and then used. The Adapter pattern is a design pattern that bridges the "gap" between "what is already provided" and "what you need". ["Introduction to Design Patterns Learned in Java Language"](https://www.amazon.co.jp/ Introduction to Design Patterns Learned in Java Language-Yuki-Hiroshi / dp / 4797327030 /)

lang_and_engine

If you use the Adapter pattern well, it also has the effect of improving interpersonal relationships within the development team. When a low-skilled person wrote a mess of code, when another member tried to rewrite the source code of the class from the side, the programmer who coded it first said that it was "hurt". I feel it. In order to avoid this, the wrapper class is made one step higher, and the wrapper class side is enriched to improve the quality.

From List of 23 GoF design patterns to utilize in Java

Finally

It's the real pleasure of programmers to be able to enjoy intellectual enjoyment just by looking at a single line of code without having to go to the museum.

If you are an engineer who sympathizes with the artistry of the Adapter pattern, please contact the hiring manager of our company (Qualysite Technologies Inc.). Contact Please!

Reference URL

Related article

Create an instance

-Design pattern to enjoy with Java library used frequently --Factory pattern -Design patterns to enjoy with frequently used Java libraries --Builder patterns -Design patterns to enjoy with frequently used Java libraries --Abstract Factory pattern

Simplify the interface

-Design patterns to enjoy with frequently used Java libraries --Facade pattern --Design patterns to enjoy with frequently used Java libraries --Adapter patterns

Leave it to another class

-Design patterns to enjoy with frequently used Java libraries --Template Method patterns -Design pattern to taste with Java library that is often used --Strategy pattern

footnote

[^ 1]: In the actual development scene, use a module management tool such as Maven to add the jar file. Please refer to Official reference of SLF4J here for the description method in the Maven configuration file (pom.xml).

[^ 2]: [Since there are too many java loggers to understand, I tried to organize them](http://www.bunkei-programmer.net/entry/2012/10/20/ java loggers I don't understand why there are too many, so organize them)

Recommended Posts

Design patterns to enjoy with frequently used Java libraries --Adapter patterns
Design patterns to enjoy with frequently used Java libraries --Builder patterns
Design patterns to enjoy with frequently used Java libraries --Strategy patterns
Design patterns to enjoy with frequently used Java libraries --Template Method patterns
Design patterns to enjoy with frequently used Java libraries --Facade pattern
Design patterns to enjoy with frequently used Java libraries --Abstract Factory pattern
Design patterns learned with Java & PHP (summary)
Docker. Set frequently used commands to alias "with explanation"
[Updated from time to time] Summary of design patterns in Java
Chapter 4 Summary of Introduction to Design Patterns Learned in Java Language
Summary of Chapter 3 of Introduction to Design Patterns Learned in Java Language