The flyweight pattern
I. What is the yuan model
Object orientation solves some flexibility or extensibility problems well, but in many cases it increases the number of classes in the system. The increasing number of classes in the system will affect the performance of the program. The share mode improves the utilization rate of system resources by using the sharing technology to improve the reuse of the same or similar objects.
Definition of Flyweight pattern: Sharing techniques are used to efficiently support reuse of large numbers of fine-grained objects. By sharing existing objects, it can greatly reduce the number of objects to be created and avoid the overhead of a large number of similar classes, thus improving the utilization rate of system resources.
The share pattern has two requirements: fineness and shared objects. With fine granularity, it is inevitable that there will be many objects with similar properties, so we divide the information about these objects into two parts: internal state and external state.
The Intrinsic State is the same as that of the insic mode, while Extrinsic State is the same as that of the external environment. The external State and internal State are independent. A change in the external state does not cause a change in the internal state. Because internal and external states are distinguished, different external states can be set so that the same object can have some different characteristics, and the same internal state can be shared. In other words, the essence of the sharing pattern is separation and sharing: separation of change and immutability, and sharing immutability.
Do you understand the internal and external states above? Let’s first understand internal states and external states. For example: I am Zhang SAN. Everyday go to work to come home. Internal state is: my invariable attribute, I call zhang SAN. The external state is: I have to go to work, go home, the change of geographical location, for example: play go. Go has black and white pieces. The internal states are: the fixed properties of Go, the colors of the pieces, and the spots/white pieces. The external states are: the change of the coordinates of the positions on the board. The user name, password, connection URL and other information stored in the connection object are set when the object is created and do not change with the environment. The external state is: When each connection is recycled, we need to mark it as available. These are the external states. Name and go black and white, connection pool connection information is a fixed property. They are all internal states. And the external state is changing. Like this, there’s a distinction between internal state and external state, so we can treat internal state as part of the share and the essence of the share pattern is to cache shared objects and reduce memory consumption.
Try to understand the above paragraph again.
-
The Intrinsic State is the same content that can be shared with the external environment, while the changes that cannot be shared with the external environment are Extrinsic State. Here go color, people’s names are not changing, they can be used as an internal state. The change of position, the change of coordinate is changed with the change of environment scene, is the external state.
-
The external state and the internal state are independent of each other, and the change of the external state does not cause the change of the internal state. If the internal state changes with the external state. That internal state is not shareable. For example, water becomes ice and becomes steam. After this external state changes, the internal state changes too, and the share mode cannot be used
-
Because internal and external states are distinguished, different external states can be set so that the same object can have some different characteristics, and the same internal state can be shared. In other words, the essence of the sharing pattern is separation and sharing: separation of change and immutability, and sharing immutability.
This sentence is a summary of the above. Use internal state as a shared object. The essence of share mode is to separate internal and external objects and share internal objects.
The factory pattern is typically found in the share pattern, where a share factory needs to be created to maintain a Flyweight Pool (for storing share objects with the same internal state).
In share mode, the internal state of the share object is shared, and the external state needs to be set by the environment. In practice, the number of internal states that can be shared is limited, so share objects are typically designed to be smaller objects that contain fewer internal states, also known as fine-grained objects.
The purpose of the share pattern is to reuse a large number of fine-grained objects using sharing technology.
The main problem solved by the share mode is that when there are a large number of objects, it may cause memory overflow, so we abstract out the common part. If there is the same business request, we directly return the existing objects in memory, avoiding re-creation.
Two. Enjoy the yuan mode when to use
2. These objects can be divided into internal states and external states. These objects can be divided into many groups according to internal states.
Case 3.
We’re going to draw 20 circles with five colors. Each circle has a random color and coordinates.
1. General implementation.
Step 1: Define a shape interface
package com.lxl.www.designPatterns.flyweight.circle;
/** * shape */
public interface Shape {
void draw(a);
}
Copy the code
Step 2: Define the circular implementation class
package com.lxl.www.designPatterns.flyweight.circle;
public class Circle implements Shape{
/** ** color */
private String color;
/** ** x coordinates */
private int x;
/** ** y coordinate */
private int y;
/** * radius */
private int radius;
public Circle(String color, int x, int y, int radius) {
this.color = color;
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw(a) {
System.out.println("Center: {" + x + "," + y + }, radius: + radius);
}
public int getX(a) {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY(a) {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getRadius(a) {
return radius;
}
public void setRadius(int radius) {
this.radius = radius; }}Copy the code
Step 3: Create 20 circles randomly in 5 colors
package com.lxl.www.designPatterns.flyweight.circle;
public class client {
private static final String colors[] =
{ "Red"."Green"."Blue"."White"."Black" };
private static String getRandomColor(a) {
return colors[(int)(Math.random()*colors.length)];
}
private static int getRandomX(a) {
return (int)(Math.random()*100 );
}
private static int getRandomY(a) {
return (int)(Math.random()*100);
}
private static int getRadius(a) {
return (int)(Math.random()*10+1);
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Shape circle = newCircle(getRandomColor(), getRandomX(), getRandomY(), getRadius()); circle.draw(); }}}Copy the code
Running results:
49, circle: {86}, radius: 8 circle: {97, 15}, radius: 5 circle: {63} 38, radius: 9 circle: {}, 76, 43, radius: 2 circle: {} 98, 47, radius: 7 circle: {2, 96}, radius: 58, 3 circle: {86}, radius: 3 circle: {64} 83, radius: 4 circle: {56, 21}, radius: 7 circle: {57, 77}, radius: 3 circle: 29} {40, and radius: 9 circle: {23, 42}, radius: Radius of circle: {89, 35}, : 3 circle: {50, 16}, radius: 4 circle: {65, 9}, radius: 5 circle: {33, 9}, radius: 7 circle: {27, 82}, radius: 9 circle: {93} 97, radius: 1 Center: {30, 99}, radius: 3 Center: {17, 18}, radius: 4Copy the code
Analysis: This is the crude way, we see to draw 20 circles, created 20 objects. If YOU draw 100 circles you have to create 100 objects. If you play Go, there are many more objects to create. The system can’t handle that.
Next, we use the share pattern optimization
2. Enjoy yuan mode optimization
Step 1: Define the shape interface
package com.lxl.www.designPatterns.flyweight.flyweightCicle;
/** * shape interface */
public interface Shape {
/ * * * * /
void draw(a);
}
Copy the code
Step 2: Define the prototype implementation class
package com.lxl.www.designPatterns.flyweight.flyweightCicle;
/** * circular implementation class */
public class Circle implements Shape{
/** * the color of the circle */
private String color;
/** ** x coordinates */
private int x;
/** ** y coordinate */
private int y;
/** * radius */
private int radius;
/ * * * * /
@Override
public void draw(a) {
System.out.println("Center: {" + x + "," + y + }, radius: + radius);
}
public Circle(String color) {
this.color = color;
}
public Circle(String color, int x, int y, int radius) {
this.color = color;
this.x = x;
this.y = y;
this.radius = radius;
}
public String getColor(a) {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getX(a) {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY(a) {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getRadius(a) {
return radius;
}
public void setRadius(int radius) {
this.radius = radius; }}Copy the code
Step 3: Enjoy yuan factory
package com.lxl.www.designPatterns.flyweight.flyweightCicle;
import java.util.HashMap;
import java.util.Map;
/** ** factory */
public class ShapeFactory {
public static Map<String, Shape> shapeMap = new HashMap<>();
public static Shape createShape(String color) {
Shape shape = shapeMap.get(color);
if (shape == null) {
shape = new Circle(color);
shapeMap.put(color, shape);
}
returnshape; }}Copy the code
In the meta factory, we define a Map collection where key is color and value is Shape. To create a shape, pass in a color and go to the map collection to get a color object. If there is one, fetch it. If there is none, create one and put it into the map.
Step 4: Client call
package com.lxl.www.designPatterns.flyweight.flyweightCicle;
public class Client {
public static String[] colors = new String[] {"red"."blue"."green"."purple"."yellow"};
private static String getRandomColor(a) {
return colors[(int)(Math.random()*colors.length)];
}
private static int getRandomX(a) {
return (int)(Math.random()*100 );
}
private static int getRandomY(a) {
return (int)(Math.random()*100);
}
private static int getRadius(a) {
return (int)(Math.random()*10+1);
}
public static void main(String[] args) {
for (int i=0; i < 20; i++) { Circle circle = (Circle)ShapeFactory.getShape(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(getRadius()); circle.draw(); }}}Copy the code
How many objects have been created? You have a few colors and you create a few objects. Create a maximum of five objects. This greatly reduces the number of objects compared to the original 20. If go has only black and white pieces, only two objects need to be created.
Step 5: Run results
Circle: {10} 25, radius: 5 circle: {99} 74, radius: 8 circle: {13, 59}, radius: 1 circle: {62, 58}, radius: 6 circle: {98} 97, radius: 9 circle: 44}, {1, radius: 8 Center: {26, 97}, radius: 10 Center: {27, 68}, radius: 8 Center: {33, 68}, radius: 7 Center: {69, 23}, radius: 9 Center: {93, 27}, radius: 6 Center: {} 72, 90, radius: 1 circle: {61} 80, radius: 2 circle: {36, 88}, radius: 3 circle: {79} 8, radius: 5 circle: {87} 29, radius: 6 circle: {48, 62}, radius: 9 circle: {7, 71}, radius: 1 circle: {0, 67}, radius: 7 circle: 22} {, 59, radius: 2Copy the code
Summary: In this, Shape is the abstract interface of the element, Circle is the object of the element, and there are two parts in the Circle object, one is the state that can be shared, namely: color; The other part is the unshareable state, namely: center + radius. These two parts combine to form the share object.
Fourthly, enjoy the structure of yuan mode
1. Summary of Enjoy Yuan model
Take a look at a UML diagram of the Meta-schema:
As you can see from the figure above, the share mode usually contains the following roles:
- FlyWeight abstract object: FlyWeight is the base class of all concrete meta-classes. It is the public interface that needs to be implemented by the specification of concrete meta-classes. The external state of non-shared elements is passed in the form of parameters through methods.
- Shareable share concrete object, ConcreteFlyWeight: Implements the abstract share docking interface, receiving external state
- Not to share the flyweight concrete object UnShareConcreteFlyWeight: is not can share external state, it takes the form of parameters into specific flyweight relevant methods
- The FlyWeightFactory is responsible for creating and managing weightweight roles. When a customer object requests a share object, the share factory checks whether there is a share object that meets the requirements in the system and provides it to the customer if there is one. If one does not exist, a new share object is created.
- The Client calls the Client
Enjoy the source code of the yuan model
Step 1: Non-shareable share element objects
package com.lxl.www.designPatterns.flyweight.demo;
/** * Unshareable share object * Here is the external state in the share object. The center and radius of the circle */
public class UnShareConcreteFlyWeight {
/** * you can define any object in this file, and name it info just for illustration */
private String info;
public UnShareConcreteFlyWeight(String info) {
this.info = info;
}
@Override
public String toString(a) {
return "UnShareConcreteFlyWeight{" +
"info='" + info + '\' ' +
'} ';
}
public String getInfo(a) {
return info;
}
public void setInfo(String info) {
this.info = info; }}Copy the code
The non-shareable share object, that is, the part of the external state that changes
Step 2: Enjoy the abstract interface
package com.lxl.www.designPatterns.flyweight.demo;
/** ** interface */
public interface FlyWeight {
/** * Share objects have different behavior results due to unshareable state *@param unshare
*/
void operate(UnShareConcreteFlyWeight unshare);
}
Copy the code
The share interface defines a operate method, a method that changes with external state
Step 3: shareable share element object, implement share element abstract interface
package com.lxl.www.designPatterns.flyweight.demo;
/** * Specifies the share object */
public class ConcreteFlyWeight implements FlyWeight{
/** * Internal state * Share objects can be grouped according to internal state */
private String innerState;
/** * Each object has an internal state when it is created *@param innerState
*/
public ConcreteFlyWeight(String innerState) {
this.innerState = innerState;
}
@Override
public void operate(UnShareConcreteFlyWeight unshare) {
System.out.println("The shared state is :"+ innerState + ", the unshared state is:" + unshare.toString());
}
public String getInnerState(a) {
return innerState;
}
public void setInnerState(String innerState) {
this.innerState = innerState;
}
@Override
public String toString(a) {
return "ConcreteFlyWeight{" +
"innerState='" + innerState + '\' ' +
'} '; }}Copy the code
This defines a shareable state that is specific to the object itself. The operate method of the parent class is also overridden.
Step 4: Enjoy yuan factory
package com.lxl.www.designPatterns.flyweight.demo;
import java.util.HashMap;
public class FlyWeightFactory {
private HashMap<String, FlyWeight> flyweights = new HashMap<String, FlyWeight>();
public FlyWeight getFlyweight(String key) {
FlyWeight flyweight = (FlyWeight) flyweights.get(key);
if(flyweight ! =null) {
System.out.println("Specific Share" + key + "Already exists, successfully retrieved!");
} else {
System.out.println("Specific Share" + key + "Doesn't exist, create one!");
flyweight = new ConcreteFlyWeight(key);
flyweights.put(key, flyweight);
}
returnflyweight; }}Copy the code
A map defined by a share factory. Key is a share object and value is a share object. Objects of the same internal state can then share an object.
Step 5: Enjoy yuan client
package com.lxl.www.designPatterns.flyweight.demo;
public class FlyWeightClient {
public static void main(String[] args) {
FlyWeightFactory factory = new FlyWeightFactory();
FlyWeight f01 = factory.getFlyweight("key1");
FlyWeight f02 = factory.getFlyweight("key1");
FlyWeight f03 = factory.getFlyweight("key1");
FlyWeight f11 = factory.getFlyweight("key2");
FlyWeight f12 = factory.getFlyweight("key2");
f01.operate(new UnShareConcreteFlyWeight("First call to key1"));
f02.operate(new UnShareConcreteFlyWeight("Second call to key1"));
f03.operate(new UnShareConcreteFlyWeight("Third call to key1"));
f11.operate(new UnShareConcreteFlyWeight("First call to key2"));
f12.operate(new UnShareConcreteFlyWeight("Second call to key2")); }}Copy the code
Running results:
Key1 does not exist, create one! Key1 already exists, obtained successfully! Key1 already exists, obtained successfully! Key2 does not exist, create one! Key2 already exists, obtained successfully! UnShareConcreteFlyWeight{info=' 1st call to key1'} The shared state is key1, the unshared state is: UnShareConcreteFlyWeight{info=' 2nd call to key1'} Share status :key1, unshare status: UnShareConcreteFlyWeight{info=' 3rd call to key1'} Share status :key2, unshare status: UnShareConcreteFlyWeight{info=' 1st call to key2'} Shared status :key2, unshared status: UnShareConcreteFlyWeight{info=' 2nd call to key2'}Copy the code
Five. Enjoy the type of yuan mode
There are two types of share mode: pure share mode and composite share mode
1. Single storage mode
What we are talking about above is pure enjoy yuan mode, here will not repeat. Next, look at the composite share pattern.
2. Composite share mode
Composite enjoy yuan pattern, difficult to understand. Be sure to match a case