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 take a closer look at the beautiful design, which can be said to be a kind of art.
Main.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Main {
public static void main(String[] args) {
//Create an instance of GSON
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new MyFieldNamingStrategy())
.create();
//Convert Java objects to JSON strings
String json = gson.toJson(new ExampleBean());
//output
System.out.println(json);
}
}
MyFieldNamingStrategy.java
import com.google.gson.FieldNamingPolicy;
import com.google.gson.FieldNamingStrategy;
import java.lang.reflect.Field;
public class MyFieldNamingStrategy implements FieldNamingStrategy {
@Override
public String translateName(Field field) {
//Of member variables"_"Get rid of
String fieldName = FieldNamingPolicy.IDENTITY.translateName(field);
if (fieldName.startsWith("_")) {
fieldName = fieldName.substring(1);
}
return fieldName;
}
}
ExampleBean.java
public class ExampleBean {
//At the beginning of member variables"_"Is attached
private String _firstField = "value";
private String _secondField = "vaule";
}
//At the beginning of a member variable"_"Is taken
{"firstField":"value","secondField":"vaule"}
This is a scene to convert a Java object to a JSON string using the Gson library. When you watch it again, you will be thrilled with the interface that seems to be both simple and customizable.
Gson is an open source library made by Google that converts Java objects <=> JSON to each other. I'm using this Gson library to convert the ʻExampleBean` class to JSON.
The ʻExampleBean` class was probably written by a C ++ or Objective-C programmer. Unusual in Java, member variables are prefixed with "\ _" (underscore). However, I don't want to add "\ _" to the JSON generated this time.
Gson is designed to set FieldNamingStrategy
to GsonBuilder
as the logic to determine the field name (JSON key name) when converting a Java object to JSON. In the "Template Method pattern" I wrote in the previous article, it was a mechanism to inherit the parent class in order to customize the function. This time, I set an instance of the class. There seems to be a design aesthetic in using inheritance as little as possible in customizing features. Let's explore together.
The code at the beginning uses the Strategy pattern, but first, let's think about what the design would look like without the Strategy pattern, as if you were the designer of the Gson library.
What I want to do is not to add "\ _" when converting a class that has "\ _" in the field name to JSON. It is assumed that there are many classes to be converted, and that the class cannot be refactored to change the field name.
Class inheritance is the first thing we talk about in object-oriented programming, so let's try designing with inheritance. Let's implement the logic that determines the field name by inheriting the Gson
class [^ 1].
MyGson.java
public class MyGson extends Gson {
@Override
protected String translateFieldName(Field field) {
//At the beginning of the field name"_"If is attached, the removed character string is returned.
// "_"If there is no, return it as it is.
}
}
Main.java
...
public class Main {
public static void main(String[] args) {
//Create an instance of GSON
Gson gson = new MyGson();
//Convert Java objects to JSON strings
String json = gson.toJson(new ExampleBean());
//output
System.out.println(json);
}
}
It's refreshing than I expected ... The MyGson
class implements the logic to translate field names by overriding the parent class's translateFieldName
method. The overridden method is called from the parent class Gson
class when creating a JSON string. This method is the "Template Method pattern" I wrote in the previous article. It's simpler and easier to understand than you can imagine.
In this situation, you can't help thinking, "It's an overwhelming victory for the Template Method pattern. I didn't have a Strategy pattern."
However, field names are not the only things that Gson can customize. Looking at Gson's Javadoc, there are many other customizable points besides field names.
Etc.
If you do all these customizations with parent class inheritance, you're in trouble. That is, the combination of features will explode.
For example, suppose you are using a class of Gson1
that overrides the function of 1 above, Gson2
that overrides the function of 2, and Gson3
that overrides the function of 3.
1 function | 2 functions | 3 features | |
---|---|---|---|
Gson1 class | ○ | ||
Gson2 class | ○ | ||
Gson3 class | ○ |
In this situation, when you need both new 1 and 2 features, you'll need a Gson12
class that overrides both methods. The source code is duplicated because the contents of the method are exactly the same as those described in Gson1
and Gson2
respectively.
1 function | 2 functions | 3 features | |
---|---|---|---|
Gson1 class | ○ | ||
Gson2 class | ○ | ||
Gson3 class | ○ | ||
Gson12 class | ○ | ○ |
Furthermore, if you need the functions 1 and 3, you need the Gson13
class as well, and if you need the functions 1, 2 and 3, you need to create the Gson123
class.
1 function | 2 functions | 3 features | |
---|---|---|---|
Gson1 class | ○ | ||
Gson2 class | ○ | ||
Gson3 class | ○ | ||
Gson12 class | ○ | ○ | |
Gson13 class | ○ | ○ | |
Gson123 class | ○ | ○ | ○ |
... |
In this way, if you try to solve it by ** inheritance of the Gson
class, the worst design is that you need as many classes as there are combinations of functions and the source code is duplicated **.
As another method using inheritance, it is possible to inherit the ʻExampleBean class that converts to JSON and implement each method such as
translateFieldName` here. However, it still encounters the same problem as above, and it goes against the Gson specification philosophy of being able to convert POJOs (ordinary Java objects) to JSON in the first place.
Now let's apply the Strategy pattern. For the source code and execution result, see [Opening](#this art) again.
The flow of this Strategy pattern is as follows.
GsonBuilder
sets MyFieldNamingStrategy
to Gson
MyFieldNamingStrategy # translateName
is called when translating a field name in Gson # toJson
The point is that the process of converting field names is delegated to MyFieldNamingStrategy
rather than directly in the Gson
class. By doing this, ** the main class (Gson
) and the conversion logic class (XXXStrategy
) can be separated **. Separation makes it easy to replace or reuse logic in a sneak peek. beautiful!
The GoF definition of the Strategy pattern is "Define a family of algorithms, encapsulate each one, and make them interchangeable. The Strategy pattern allows the algorithm used by the client to be modified independently. [^ 2] ". The "algorithm family" here corresponds to functions such as converting field names (XXXStrategy
class).
Many experts have also commented on evaluating the Strategy pattern.
Hiroshi Yuki
In the Strategy pattern, the part that implements the algorithm can be exchanged in a sneak peek. The Strategy pattern is a pattern that makes it easy to switch algorithms (strategies, strategies, strategies) and solve the same problem in different ways.
["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
When it comes to a somewhat complicated algorithm, a normal programmer will cut out and aggregate that part. It should also be compatible in case it is replaced by another algorithm.
It's the real pleasure of programmers to be able to enjoy intellectual enjoyment by just looking at a few lines of code without having to go to the museum.
If you are an engineer who sympathizes with the artistry of the Strategy pattern, please contact the recruiting staff of our company (Qualysite Technologies Inc.). Contact Please!
In the above example, the FieldNamingStrategy
class was used to convert the field name in Gson, but you can also decide the name in JSON by just annotating the member variables of the class to be converted. This is convenient when there are few classes to be converted.
ExampleBean.java
public class ExampleBean {
@SerializedName("firstField")
private String _firstField = "value";
@SerializedName("secondField")
private String _secondField = "vaule";
}
-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
-Design patterns to enjoy with Java libraries that are often used --Facade patterns -Design pattern to enjoy with frequently used Java library --Adapter pattern
-Design patterns to enjoy with frequently used Java libraries --Template Method patterns --Design patterns to enjoy with frequently used Java libraries --Strategy patterns
[^ 1]: The Gson class is declared final and cannot actually be inherited. Assuming that you are the designer of Gson, you are in the process of considering what kind of design you should make. [^ 2]: ["Design pattern for reuse in object orientation"](https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8 % E3% 82% A7% E3% 82% AF% E3% 83% 88% E6% 8C% 87% E5% 90% 91% E3% 81% AB% E3% 81% 8A% E3% 81% 91% E3 % 82% 8B% E5% 86% 8D% E5% 88% A9% E7% 94% A8% E3% 81% AE% E3% 81% 9F% E3% 82% 81% E3% 81% AE% E3% 83 % 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% 91% E3% 82% BF% E3% 83% BC% E3% 83% B3-% E3% 82% AC% E3% 83% B3% E3% 83% 9E-% E3% 82% A8% E3% 83% AA% E3% 83% 83% E3% 82% AF / dp / 479731126 / ref = sr_1_1? Ie = UTF8 & qid = 1495503419 & sr = 8-1 & keywords =% E3% 82% AA% E3% 83% 96% E3% 82% B8% E3% 82% A7% E3% 82% AF% E3% 83% 88% E6% 8C% 87% E5% 90% 91% E3% 81% AB% E3% 81% 8A% E3% 81% 91% E3% 82% 8B% E5% 86% 8D% E5% 88% A9% E7% 94% A8% E3% 81% AE% E3% 81% 9F% E3% 82% 81% E3% 81% AE% E3% 83% 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% From 91% E3% 82% BF% E3% 83% BC% E3% 83% B3)
Recommended Posts