Application example of design pattern (No. 1)

at first

** "It's easy to make simple things complicated, but it's difficult to make complicated things easy" ** is my theory.

In the field, when given a task, we often see programmers trying to solve problems by lining up the code without thinking too much. Over and over again, the source code becomes more and more complex, unreadable, and unmaintainable.

It is a good idea to consider the mechanism and algorithm as much as possible before starting. This not only makes problems that look complicated (in some cases dramatically) look simple, but also brings other benefits such as increased reusability and increased productivity.

Design patterns are often useful in this case. In the function implementation of general business systems, most of the common functions are covered by frameworks and common libraries, so there are not many situations where design patterns are used. However, it is often used in the frameworks and common libraries on which it is based. Many of you may be familiar with the patterns below, but they are the ones that are often used.

Task

This is an example in product development, but if you have knowledge of design patterns, please try to solve the following problems.

Nowadays, it is an exaggeration to say that the development of business systems is inevitable for the use of OSS libraries, unlike in the past. Speaking of OSS libraries, some are major and some are not well known. Whatever it is, it will be upgraded or eliminated due to the evolution of the times. In that case, there are design patterns that we often use to avoid being affected by changes in the library as much as possible.

So the problem: Java development uses JSON OSS libraries such as GSON and Jackson for mutual conversion between data beans and JSON strings. Suppose you might replace that library with another in the future. When upgrading the version of the library you are using or replacing it with another library, how should you apply the design pattern to minimize the impact on the existing source? Think about it here before looking at the second half of the article.

Solution example

We solve this problem by utilizing the Adapter pattern of the design pattern. This is not the only solution, so if you have any other comments, please comment. If you want to know the details of Adapter pattern, please refer to Apater pattern | TECK SCORE.

When using the Adapter pattern, there are the following two types of mounting methods.

There was a requirement that it could be replaced with another library in the future, so using inheritance will have a greater impact on existing sources. Here, "implementation using delegation" is adopted.

Implementation sample

The following is an implementation sample. (Simplified for the article.) Even if you replace it with another library in the future, the implementation on the user side should be able to handle it with almost no change.

Target interface

package json;

import java.io.InputStream;
import java.io.OutputStream;

/**
 *
 *JSON Target interface
 *
 */
public interface JsonAdapterIF {

    /**
     *Target method(Read JSON string)
     */
    <T> T read(String json, Class<T> type) throws Exception;

    /**
     *Target method(Read JSON Input Stream)
     */
    <T> T read(InputStream is, Class<T> type) throws Exception;

    /**
     *Target method(Write to JSON string)
     */
    String write(Object obj) throws Exception;

    /**
     *Target method(Write to JSON Output Stream)
     */
    void write(Object obj, OutputStream os) throws Exception;

}

Adapter

package json;

import java.io.InputStream;
import java.io.OutputStream;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 *JSON Adapter class(Jackson)。
 */
public class JacksonAdapter implements JsonAdapterIF {

    /** Adaptee (Jackson's ObjectMapper) */
    private ObjectMapper om;

    /**
     *Protected so that you cannot create an instance of Adapter directly from the user side
     *The qualifier hides the constructor.
     */
    protected JacksonAdapter() {
        this(new ObjectMapper());
    }

    /**
     *Protected so that you cannot create an instance of Adapter directly from the user side
     *The qualifier hides the constructor.
     */
    protected JacksonAdapter(ObjectMapper om) {
        // the om must not be null
        assert om != null;
        this.om = om;
    }

    @Override
    public <T> T read(String json, Class<T> type) throws Exception {
        return om.readValue(json, type);
    }

    @Override
    public <T> T read(InputStream is, Class<T> type) throws Exception {
        return om.readValue(is, type);
    }

    @Override
    public String write(Object obj) throws Exception {
        return om.writeValueAsString(obj);
    }

    @Override
    public void write(Object obj, OutputStream os) throws Exception {
        om.writeValue(os, obj);
    }

}

Factory (bonus)

package json;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 *Factory class for creating JSON Adapter.
 *Since it is not possible to create an instance of Adapter directly on the client side, a factory is provided.
 */
public class JsonAdapterFactory {

    /** A thread safe map of JsonAdapter */
    private static Map<Class<?>, JsonAdapterIF> omMap = new ConcurrentHashMap<>();

    static {
        //Default JSON Adapter (for any class)
        omMap.put(Object.class, new JacksonAdapter());

        //Create another ObjectMapper if special initialization is required
        ObjectMapper om = new ObjectMapper();
        //Abbreviation
        omMap.put(Special class.class, new JacksonAdapter(om));
    }

    private JsonAdapterFactory() {
    }

    /**
     *Get the default JSON Adapter.
     */
    public static JsonAdapterIF getJsonAdapter() {
        return omMap.get(Object.class);
    }

    /**
     *Get a JSON Adapter for a special class.
     */
    public static JsonAdapterIF getJsonAdapter(Class<?> clazz) {
        return omMap.get(clazz);
    }

}

Zhou @ Soft Sink

Recommended Posts

Application example of design pattern (No. 1)
Design pattern ~ Chain of Responsibility ~
Design pattern ~ Builder ~
Design pattern ~ Visitor ~
Java design pattern
Design pattern ~ Proxy ~
Design pattern ~ State ~
Design pattern ~ Strategy ~
Design pattern ~ Composite ~
Design pattern (1): AbstractFactory
Design pattern ~ Iterator ~
Design pattern ~ Facade ~
Design pattern ~ Bridge ~
Design pattern ~ Decorator ~
Design pattern ~ Interpreter ~
Design pattern ~ Observer ~
Design pattern ~ Prototype ~
Design pattern ~ Memento ~
Design pattern ~ Adapter ~
Design pattern ~ Flyweight ~
Web application menu display condition design / code example
PrintObserver "Observer Design Pattern: Description and Implementation Example"
C ++ design pattern (TemplateMethod pattern)
Design pattern ~ Factory Method ~
Design pattern ~ Abstract Factory ~
[No.006] Rough design of organization management screen and login
Example of using vue.config.js
Chain Of Responsibility pattern
GoF design pattern summary
Design pattern ~ Template Method ~
Java design pattern summary
Java8 Lambda Expression & Stream Design Pattern Rethinking --Chain of Responsibility Pattern -
Example of params using where
Example of using abstract class
[Design pattern] Java core library
[Java] Summary of design patterns