“This is the 20th day of my participation in the August Genwen Challenge.More challenges in August”

First, the origin of the yuan model

Object-oriented technology can solve some flexibility or extensibility problems well, but in many cases it is necessary to increase the number of classes and objects in the system. When the number of objects is too large, the operation cost is too high, resulting in performance degradation. Enjoy yuan mode is to solve this kind of problem and was born.

Flyweight Pattern, also known as lightweight Pattern, is an implementation of object pool. Similar to thread pools, thread pools avoid the performance cost of constantly creating and destroying multiple objects. Provides a way to reduce the number of objects to improve the object structure required by the application. Its purpose is to share fine-grained objects, centralize multiple access to the same object, do not have to create a separate object for each visitor, in order to reduce memory consumption, belongs to the structural pattern.

Two, enjoy the definition of yuan mode

The sharing mode divides the state of an object into internal state and external state. The internal state is unchanged, and the external state is changed. Then, by sharing the unchanged part, the number of objects is reduced and the purpose of saving memory is achieved.

The essence of share mode is to cache shared objects and reduce memory consumption.

3. Roles involved in enjoy Mode

  1. Abstract Flyweight: A Flyweight object abstracts the base class or interface, defining both the external state of the object and the interface or implementation of its internal state.
  2. ConcreteFlyweight: A business that implements abstract role definitions. The role’s internal state handling should be context-specific, and there should not be an operation that changes the internal state and modifies the external state.
  3. FlyweightFactory: Manages the pool of weightobjects and creates weightobjects.

Fourthly, the application scenario of enjoy yuan mode

When multiple places in the system need the same set of information, you can encapsulate the information into an object and cache the object. In this way, one object can be provided to multiple places, avoiding multiple creation of the same object and consuming a large amount of memory space.

In fact, the share mode is an improved mechanism of the factory mode. The share mode also requires the creation of an object or a group of objects, and it is through the factory method to generate objects, but the share mode for the factory method to increase the cache function.

Mainly summarized as the following application scenarios:

  1. It is often applied to the development of the bottom layer of the system to solve the performance problems of the system.
  2. Scenarios where the system has a large number of similar objects and requires a buffer pool.

In daily life, yuan sharing mode is also common, such as the housing resource sharing of various intermediary agencies, and the national social security network.

5. Use the share mode to realize the sharing pool service

For example, every Spring Festival, in order to get a train ticket home, we have to go through a lot of trouble, so there are many ticket brushing software, which will cache the information we fill in, and then regularly check the remaining ticket information. When grabbing tickets, we must check whether there is any ticket information we need. Here, we assume that the information of a train includes: departure station, destination station, price and seat type. Now it is required to simulate a pseudo-code query train ticket, which can check the relevant ticket information through the departure station and destination station. So we just need to build the train ticket class object, and then provide a query departure station, the destination station interface to the customer to query, the specific code is as follows, create the ITicket interface:

public interface ITicket {
    void showInfo(String bunk);
}
Copy the code

Then create the TrainTicket interface:

public class TrainTicket implements ITicket {

    private String from;
    private String to;
    private int price;

    public TrainTicket(String from, String to) {
        this.from = from;
        this.to = to;
        this.price = new Random().nextInt(600);
    }

    @Override
    public void showInfo(String bunk) {
        System.out.println(String.format("% S ->%s: %s Price: %s $.this.from, this.to, bunk, this.price)); }}Copy the code

Finally create the TicketFactory class:

public class TicketFactory {

    public static ITicket queryTicket(String from, String to) {
        return newTrainTicket(from, to); }}Copy the code

Write client code:

public class Test {

    public static void main(String[] args) {
        ITicket ticket = TicketFactory.queryTicket("Linfen West"."Beijing West");
        ticket.showInfo("Train"); }}Copy the code

By analyzing the above code, we find that when the client queries, the system directly creates a train ticket object through TicketFactory. However, when a large number of users request information about the same ticket at a certain moment, the system will create a large number of such train ticket objects, resulting in a sudden increase in the system memory pressure. In fact, it is better to cache this ticket object and reuse it for other query requests, so that an object can meet the requirements to support thousands of query requests, and there is no pressure on memory. Using the share mode can be a good solution to this problem. We continue to optimize the code by making changes in the TicketFactory class to add a caching mechanism:

public class TicketFactory {

    private static Map<String, ITicket> ticketPool = new ConcurrentHashMap<>();

    public static ITicket queryTicket(String from, String to) {
        String key = from + "- >" + to;
        if (ticketPool.containsKey(key)) {
            System.out.println("Use cache:" + key);
            return ticketPool.get(key);
        }
        System.out.println("First query, create object:" + key);
        ITicket ticket = new TrainTicket(from, to);
        ticketPool.put(key, ticket);
        returnticket; }}Copy the code

Modify the client code:

public class Test {

    public static void main(String[] args) {
        ITicket ticket = TicketFactory.queryTicket("Linfen West"."Beijing West");
        ticket.showInfo("Train");
        ticket = TicketFactory.queryTicket("Linfen West"."Beijing West");
        ticket.showInfo("Train");
        ticket = TicketFactory.queryTicket("Linfen West"."Beijing West");
        ticket.showInfo("Train"); }}Copy the code

The running results are as follows:

As can be seen, except for the first query to create an object, the subsequent query of the same train ticket information is using the cache object, no need to create a new object.

For example, we often use the database Connection pool, because the main performance consumption when we use the Connection object is to establish and close the Connection. In order to improve the performance of the Connection in the call, we create the cache of the Connection object before the call, and use the value from the cache. Use it and then put it back to achieve the purpose of resource reuse.

Six, enjoy yuan mode in the application of the source code

1. Share mode in String

Java defines the String class as final (immutable). JVM strings are usually stored in the String constant pool. Java ensures that there is only one copy of a String in the constant pool, which was in the constant pool before JDK6.0. The JVM takes it out of the permanent generation and places it in the heap.

Let’s take a test:

public class StringTest {

    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        String s3 = "he" + "llo";
        String s4 = "hel" + new String("lo");
        String s5 = new String("hello");
        String s6 = s5.intern();
        String s7 = "h";
        String s8 = "ello";
        String s9 = s7 + s8;
        System.out.println(s1 == s2);//true
        System.out.println(s1 == s3);//true
        System.out.println(s1 == s4);//false
        System.out.println(s1 == s5);//false
        System.out.println(s1 == s6);//true
        System.out.println(s4 == s5);//false
        System.out.println(s1 == s9);//false}}Copy the code

The String class is final, and when a String variable is created as a literal, the JVM puts that literal “hello” into the String constant pool at compile time, which is loaded into memory when the Java program is started. The character of this string constant pool is that there is one and only one copy of the same literal. If there are other identical literals, the JVM returns a reference to that literal. If there are no identical literals, the literal is created in the string constant pool and returns a reference to it.

Since the literal “hello” to which S2 refers already exists in the constant pool (s1 precedes S2), the JVM returns a reference to the literal binding, so s1==s2.

The concatenation of s3 literals is simply “hello”, and the JVM optimizes it at compile time, so s1 and S3 are equal.

New String(“lo”) in S4 generates two objects, lo, new String(“lo”), lo in the String constant pool, new String(“lo”) in the heap, String s4 = “hel” + new String(“lo”) is essentially the addition of two objects, the compiler does not optimize, the result of the addition is stored in the heap, while s1 is stored in the String constant pool, of course not equal. S1 is equal to s9, same thing.

S4 ==s5 the sum of the two is both in the heap and, needless to say, definitely not equal.

S1 = = s6, s5. Intern () method can be a heap in the string at run time dynamic join the string constant pool (string constant pool is the content of the program start was loaded ok), if the string constants in the pool of the object literal, it returns the literal string constant pool in the reference, otherwise, Creates a copy of the literal into the string constant pool and returns a reference to it. So s1==s6 prints true.

2. Integer Indicates the share element mode

Integer: Integer Integer: Integer Integer: Integer Integer: Integer Integer

public class IntegerTest {

    public static void main(String[] args) {
        Integer a = Integer.valueOf(100);
        Integer b = 100;

        Integer c = Integer.valueOf(1000);
        Integer d = 1000;

        System.out.println("a==b:" + (a == b));//true
        System.out.println("c==d:" + (c == d));//false}}Copy the code

This result is obtained because Integer uses the free element schema.

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
Copy the code

We see that the valueOf() method in the Integer source code makes a conditional judgment that if the target value is between -128 and 127, the value is directly fetched from the cache, otherwise a new object is created. So why does the JDK do this? Since data between -128 and 127 is the most frequently used in the int range, to save memory consumption caused by frequent object creation, we use the free element mode to improve performance.

Seven, enjoy the internal state and external state of the yuan mode

The definition of the share pattern imposes two requirements: fineness and shared objects. Since fine-grained objects are required, it is inevitable that there will be a large number of objects with similar properties. At this point, we divide the information of these objects into two parts: internal state and external state.

Internal state refers to the information shared by the object, stored inside the share element object and does not change with the change of the environment. External state refers to a tag on which the object can depend. It is the state that changes with the change of the environment and cannot be shared.

For example, the connection object in the connection pool, the user name, password, connection URL and other information stored in the connection object are set when the object is created and will not change with the environment. These are internal states. And when each connection is recycled, we need to mark it as available, and these are external states.

Eight, enjoy the advantages and disadvantages of the yuan model

Advantages:

  1. Reduce object creation, reduce the number of objects in memory, reduce system memory, improve efficiency.
  2. Reduce the usage of resources other than memory.

Disadvantages:

  1. Focus on internal and external state and focus on thread safety.
  2. Complicates the logic of a system program.

9. Friendship links

Design Patterns – Factory Patterns learning tour

Design Patterns – a learning tour of singleton patterns

Design Patterns – A learning journey of prototyping patterns

Design Patterns – Builder patterns learning tour

Design Patterns – Agent patterns learning tour

Design Patterns – A learning tour of facade patterns

Design Patterns – A learning tour of decorator patterns

Welcome to follow the wechat public account (MarkZoe) to learn from and communicate with each other.