Design Pattern Series: http://aphysia.cn/categories/designpattern

1

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.

Offer All Solutions PDF

Open Source Programming Notes


秦怀杂货店
147 声望38 粉丝

山高水长,纵使缓慢,驰而不息。