Design Pattern Series: http://aphysia.cn/categories/designpattern
The opening is still that kind of picture, all the guests, look down...
What is the flyweight pattern?
FlyWeight
mode ( 061e0cb1b994b7 ) is a kind of structural mode, mainly to reduce the number of created objects, reduce memory usage and improve performance. Speaking of this, I don't know if you will think of pooling technologies, such as String
constant pools, database connection pools, buffer pools, etc. Yes, these all apply the Flyweight pattern.
For example, some objects require a lot of resources when they are created, the cost of creation is relatively high, and the memory overhead is relatively large. If we keep creating them and the machine cannot bear it, then we think of the pooling technology and put the created objects in it. When the time comes, just go to the pool to get it, that is, everyone shares the objects in the pool, which is sharing.
Listening to the name, it is very sharing bicycles:
Features of Flyweight Mode
Generally speaking, Flyweight objects need to be used in different scenarios. If the state can be modified at will, it is easy to cause confusion and the probability of errors is greatly increased. However, if all internal properties are unmodifiable, it does not seem to be very flexible. Therefore, in order to find a balance between stability and flexibility, general Flyweight objects will divide internal properties into two categories:
- Internal state: immutable and shared in multiple places, reused parts can only be set through constructors
- External state: each object, in different scenarios, may have different states that can be modified
- Simple flyweight mode: In the simple flyweight mode, all specific flyweight classes can be shared, and there is no non-shared specific flyweight class.
- Composite flyweight pattern: Combine some simple flyweight objects using the combination pattern, and can also form composite flyweight objects. Such composite flyweight objects cannot be shared, but they can be decomposed into simple flyweight objects, which can be shared
Here we are talking about the pure flyweight mode, which generally has several objects:
Flyweight
interface or abstract class ( 061e0cb1b995e3 ): Public methods are declared and defined in an interface or abstract class, which can provide some external capabilities or provide data on demand.ConcreteFlyweight
implementation class ( 061e0cb1b99601 ): implements the abstract flyweight class, and some internal data is immutable. When implementing the interface, it will provide some capabilities or data to the outside world.FlyweightFactory
Factory ( 061e0cb1b99628 ): Flyweight Factory is mainly used to create and manage Flyweight objects. It puts various types of Flyweight objects into a pool, usually in the form of key-value pairs, but of course it can also be other If an object is acquired for the first time, it needs to be created first. If the object already exists in the pool, it can be returned directly.
accomplish
For example, if we go out to play, we need to buy a plane ticket. Suppose the uniqueness of a flight is related to the flight number, departure time, and arrival time. Users like to check flight related information through the flight number. First, we need to create One interface for flight:
public interface IFlight {
void info();
}
Specific flight class Flight
:
public class Flight implements IFlight {
private String flightNo;
private String start;
private String end;
private boolean isDelay;
public Flight(String flightNo, String start, String end) {
this.flightNo = flightNo;
this.start = start;
this.end = end;
isDelay = Math.random() > 0.5;
}
@Override
public void info() {
System.out.println(String.format("从[%s]到[%s]的航班[%s]: %s ",
start, end, flightNo, isDelay ? "延误起飞" : "正常起飞"));
}
}
Flight Search Factory Class FlightSearchFactory
:
public class FlightSearchFactory {
public static IFlight searchFlight(String flightNo,String start,String end){
return new Flight(flightNo,start,end);
}
}
Simulate client request:
public class ClientTest {
public static void main(String[] args) {
IFlight flight = FlightSearchFactory.searchFlight("C9876","北京","上海");
flight.info();
}
}
We can see that the following information is printed:
从[北京]到[上海]的航班[C9876]: 延误起飞
However, there is a problem with the above. Every time you visit, an object will be created. In theory, people who take the same flight are querying the same data. This part can actually be shared and reused to improve efficiency. Why? Happy but not?
How to cache it?
We generally use HashMap
to cache, just define key
import java.util.HashMap;
import java.util.Map;
public class FlightSearchFactory {
private static Map<String, IFlight> maps = new HashMap<>();
public static IFlight searchFlight(String flightNo, String start, String end) {
String key = getKey(flightNo, start, end);
IFlight flight = maps.get(key);
if (flight == null) {
System.out.print("缓存中没有,需要重新构建:");
flight = new Flight(flightNo, start, end);
maps.put(key, flight);
}else{
System.out.print("从缓存中读取数据:");
}
return flight;
}
private static String getKey(String flightNo, String start, String end) {
return String.format("%s_%s_%s", flightNo, start, end);
}
}
Test code:
public class ClientTest {
public static void main(String[] args) {
IFlight flight = FlightSearchFactory.searchFlight("C9876","北京","上海");
flight.info();
IFlight flight1 = FlightSearchFactory.searchFlight("C9876","北京","上海");
flight1.info();
IFlight flight2 = FlightSearchFactory.searchFlight("H1213","北京","广州");
flight2.info();
}
}
Test Results:
缓存中没有,需要重新构建:从[北京]到[上海]的航班[C9876]: 正常起飞
从缓存中读取数据:从[北京]到[上海]的航班[C9876]: 正常起飞
缓存中没有,需要重新构建:从[北京]到[广州]的航班[H1213]: 正常起飞
It can be seen that if there is one in the cache, the object will not be rebuilt, and the purpose of sharing the object can be achieved. The various connection pools we usually use in the project, such as Redis
connection pool, Mysql
connection pool, etc., these resources are essentially Both are more precious and we can share.
JDK
in Integer
actually use cache technology, because we used are smaller value, so the default Integer
If you use valuesOf(int i)
method to obtain, priority will read the contents of the cache:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
We can see that if low
and high
, it will be obtained from the cache, otherwise a new object will be created directly, so how big is the range of low
and high
static final int low = -128;
static final int high;
high
is dynamic, but high
is asserted and must be greater than or equal to 127
: assert IntegerCache.high >= 127;
, and the range can be read from the configuration item java.lang.Integer.IntegerCache.high
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
have a test:
public class IntegerTest {
public static void main(String[] args) {
// 不相等
Integer integer = Integer.valueOf(128);
Integer integer1 = Integer.valueOf(128);
System.out.println(integer == integer1);
// 相等
Integer integer2 = Integer.valueOf(127);
Integer integer3 = Integer.valueOf(127);
System.out.println(integer2 == integer3);
// 相等
Integer integer4 = Integer.valueOf(0);
Integer integer5 = Integer.valueOf(0);
System.out.println(integer4 == integer5);
// 相等
Integer integer6 = Integer.valueOf(-128);
Integer integer7 = Integer.valueOf(-128);
System.out.println(integer6 == integer7);
// 不相等
Integer integer8 = Integer.valueOf(-129);
Integer integer9 = Integer.valueOf(-129);
System.out.println(integer8 == integer9);
}
}
From the above results, we can see that Integer
actually cached from -128
to 127
, which also verifies our results. Note that Integer.valueOf()
must be used. If the constructor new Integer()
, it must be a new object.
Summarize
- Advantages: If there are many similar or repeated objects, using flyweight mode can save space
- Disadvantages: If there is a lot of reuse, special processing is also done in different places, and the code complexity increases
The design pattern is actually a common design idea summed up in the continuous exploration of software engineering. It is not necessary, not a silver bullet, but there is always something worth learning, understanding the benefits of such a design, and constantly. Improvements We write code, even a little bit at a time. I once heard a sentence: when you see other people's inelegant code, you have the urge to refactor it, you can read more of your own code, and then write better (roughly this means). mutual encouragement!
【About the author】 :
Qin Huai, Qin Huai Grocery Store 161e0cb1b99a03 ], personal website: http://aphysia.cn , the road of technology is not at one time, the mountains and rivers are long, even if it is slow, it will never stop.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。