Introducing the design patterns of [GoF](https://ja.wikipedia.org/wiki/Gang of for _ (Information Engineering)) ["Introduction to Design Patterns Learned in the Augmented and Revised Java Language"]( https://www.amazon.co.jp/ Supplementary Revised Edition Introduction to Design Patterns Learned in Java Language-Hiroshi Yuki / dp / 4797327030 / ref = pd_lpo_sbs_14_t_0? _ Encoding = UTF8 & psc = 1 & refRID = 2ZE4GPYNN55JGDR5QMHP I will summarize about.
It is the "flyweight", which is a lightweight boxing class. The lightweight class means "lightness", which means that it consumes less memory. To create an object, you need to do new and allocate memory (instantiation), but if you create many objects, it will consume a lot of memory and the processing speed will be slow. To solve these problems, it is advisable to use it repeatedly for instances that have already been new. The pattern that suppresses memory consumption by sharing ** objects without newing as much as possible ** is called the ** Flyweight pattern **.
The Flyweight pattern is used by the classes that appear in the class diagram below.
Flyweight Represents a class to be shared and used. There are no particular methods to implement, so there are no difficulties.
FlyweightFactory
This class serves as a factory for generating Flyweight
.
If you create a Flyweight role through this factory role, you will have a method that allows you to share an instance.
It has a pool
field to store the shared instance and a getFlyewight
method to get the Flyweight.
Client
It is a class that uses Flyweight by using FlyweightFactory
.
As with Flyweight, there are no specific methods to implement, so there are no difficulties.
As a concrete example, it will be explained based on the following class.
-** Stamp class **
Stamp.java
package sample;
public class Stamp {
//letter
private char charname;
//Number of times of use
private int useCount = 0;
//Number of generations
private int newCount = 0;
public int getUseCount() {
return useCount;
}
public void setUseCount(int useCount) {
this.useCount = useCount;
}
public int getNewCount() {
return newCount;
}
public void setNewCount(int newCount) {
this.newCount = newCount;
}
//constructor
public Stamp(char charname) {
this.charname = charname;
}
//Display characters
public void print() {
System.out.println("charname:" + this.charname);
}
}
The Stamp
class is a shared and used Flyweight class.
It receives the character charname
, is generated, and prints the character with the print
method.
Also, the number of uses (ʻuseCount) and the number of generations (
newCount`) are provided with fields so that they can be easily understood, but they are not required.
-** StampFactory class **
StampFactory.java
package sample;
import java.util.HashMap;
import java.util.Map.Entry;
public class StampFactory {
//Manage already generated Stamp instances
private HashMap<String, Stamp> pool = new HashMap<>();
//Singleton pattern
private static StampFactory singleton = new StampFactory();
//constructor
private StampFactory() {
}
//Get a singleton instance
public static StampFactory getInstance() {
return singleton;
}
//Instantiation of Stamp(share)
public synchronized Stamp getStamp(char charname) {
//Key(letter)Value associated with(Stamp instance)To get
Stamp bc = pool.get("" + charname);
//Key(letter)Value associated with(Stamp instance)If could not be obtained
if (bc == null) {
//Create an instance of Stamp here
bc = new Stamp(charname);
//Count the number of new
bc.setNewCount(bc.getNewCount() + 1);
//Store in HashMap
pool.put("" + charname, bc);
}
//Count the number of uses regardless of the presence or absence of new
bc.setUseCount(bc.getUseCount() + 1);
return bc;
}
//Output all Stamp instances managed by HashMap
public void printAllPool() {
for (Entry<String, Stamp> entry : pool.entrySet()) {
System.out.println(
entry.getKey() + " : " + entry.getValue().getUseCount() + " : " + entry.getValue().getNewCount());
}
}
}
This class serves as the FlayweightFactory, which is the factory that generates the Stamp
class.
It has a pool
field as a Map for managing the generated instances and a singleton
field that represents itself because it applies the Singleton pattern here.
To use this class, first call the getInstance
method from the outside to return the StampFactory instance that represents itself.
Then, for the returned StampFactory instance, call the getStamp
method with charname
as an argument.
If a Stamp instance with the charname passed as an argument as a key has already been created, it will be obtained from pool
, but if the instance has not been created yet, an instance will be created and stored in pool
. To do.
Also, when an instance is created, +1 is added to newCount
, and ʻuseCountis increased by +1 regardless of whether or not an instance is created, so that the number of times each Stamp instance is created and used is counted. In addition,
printAllPool` is implemented as a method to output all Stamp instances stored in pool.
The output content is "Key characters: Number of uses: Number of generations".
-** Main class **
Main.java
package sample;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
//Stamp instance preparation
StampFactory factory = StampFactory.getInstance();
ArrayList<Stamp> stamps = new ArrayList<>();
stamps.add(factory.getStamp('a'));
stamps.add(factory.getStamp('b'));
stamps.add(factory.getStamp('c'));
stamps.add(factory.getStamp('f'));
stamps.add(factory.getStamp('e'));
stamps.add(factory.getStamp('a'));
stamps.add(factory.getStamp('b'));
stamps.add(factory.getStamp('c'));
stamps.add(factory.getStamp('d'));
stamps.add(factory.getStamp('f'));
stamps.add(factory.getStamp('a'));
for (Stamp s : stamps) {
s.print();
}
System.out.println("-------------------------------");
System.out.println("charname : useCount : newCount");
//Output all Stamp instances managed by HashMap
factory.printAllPool();
}
}
It is a class that serves as a Client that uses Flyweight and FlyweightFactory. By calling the getInstance method, which is a static method of the StampFactory class, to get the stampFactory instance, and calling the getStamp method for the obtained stampFactory instance, the stamp instance is stored in the pool field. Finally, by calling printAllPool (), all pool fields are output.
The result of executing Main.java
is as follows.
Even for characters whose ʻuseCount is greater than 1, the
newCount` is only once, indicating that the instance is being reused.
Execution result
charname:a
charname:b
charname:c
charname:f
charname:e
charname:a
charname:b
charname:c
charname:d
charname:f
charname:a
-------------------------------
charname : useCount : newCount
a : 3 : 1
b : 2 : 1
c : 2 : 1
d : 1 : 1
e : 1 : 1
f : 2 : 1
By using the Flyweight pattern, you can reduce the number of times you renew an object and save memory. On the other hand, the disadvantage is that the objects stored in the pool are not subject to garbage collection and remain in memory, so it is necessary to manage them intentionally so as not to run out of memory.
You learned about the Flyweight pattern, which reduces memory consumption by sharing instances. The sample code is uploaded below, so please refer to it if you like.
In addition, other design patterns are summarized below, so please refer to them as well.
-[Updated from time to time] Summary of design patterns in Java
-[Introduction to Design Patterns Learned in the Augmented and Revised Java Language](https://www.amazon.co.jp/ Introduction to Design Patterns Learned in the Augmented and Revised Java Language-Hiroshi Yuki / dp / 4797327030 / ref = pd_lpo_sbs_14_t_0? _Encoding = UTF8 & psc = 1 & refRID = 2ZE4GPYNN55JGDR5QMHP)
Recommended Posts