Enjoy yuan mode of Neusoft training

brief introduction

Use sharing to support large numbers of fine-grained objects efficiently.
Using shared objects can effectively support a large number of fine-grained objects.

Flyweight mode Also known as lightweight pattern, it is an object structured pattern.

Object oriented technology can solve some flexibility or scalability problems, but in many cases, it is necessary to increase the number of classes and objects in the system. When there are too many objects, the running cost will be too high, resulting in performance degradation and other problems. Sharing element mode It was born to solve this kind of problem.

Sharing element mode Is an implementation of object pool. Similar to thread pool, thread pool can avoid creating and destroying multiple objects and consuming performance. Sharing element mode It is also to reduce the use of memory and avoid a large number of repeated scenes of creating and destroying objects.

Sharing element mode The purpose of is to share fine-grained objects and centralize multiple accesses to the same object without creating a separate object for each visitor, so as to reduce memory consumption.

Sharing element mode The state of an object is divided into internal state and external state. The internal state is constant and the external state is changing; Then, by sharing the unchanged part, the number of objects and memory are reduced.

Sharing element mode Essence: cache shared objects to reduce memory consumption

Main solution

When the same set of information is needed in multiple places in the system, these information can be encapsulated into an object, and then the object can be cached. In this way, an object can be provided to multiple places that need to be used, avoiding multiple creation of a large number of the same object and consuming a large amount of memory space.

Sharing element mode Actually Factory mode An improved mechanism, Sharing element mode It is also required to create one or a group of objects, and the objects are generated through the factory method, but Sharing element mode Caching is added to factory methods in.

Advantages and disadvantages

advantage

  • Sharing element mode It can greatly reduce the number of objects in memory, so that the same object or similar object can only save one copy in memory, reduce the memory occupation and enhance the performance of the program;
  • Sharing element mode The external state of is relatively independent and will not affect its internal state, so that the shared meta objects can be shared in different environments;

shortcoming

  • Sharing element mode Making the system more complex, it is necessary to separate the internal state from the external state, which makes the logic of the program more complex;
  • In order for objects to be shared, Sharing element mode The state of the shared meta object needs to be externalized, and the external state must be solidified and should not change with the change of the internal state, otherwise it will lead to the logical confusion of the system;

Usage scenario

  • There are a large number of similar objects in the system;
  • Fine grained objects have close external states, and the internal state is independent of the environment, that is, the object has no specific identity;
  • Scenarios requiring buffer pools;

Mode explanation

First, let's take a look Sharing element mode General UML class diagram for:

Sharing element mode

From the UML class diagram, we can see that, Sharing element mode There are three main roles:

  • Abstract Flyweight: it abstracts the base class or interface of the meta object, and defines the interface or implementation of the external state and internal state of the object;
  • Concrete flyweight: implements the business defined by the abstract role. The internal status processing of the role should be independent of the environment. There can be no operation to change the internal status and modify the external status at the same time;
  • FlyweightFactory: responsible for managing the shared object pool and creating shared objects;

Here is Sharing element mode Common code for:

class Client {
    public static void main(String[] args) {
        IFlyweight flyweight1 = FlyweightFactory.getFlyweight("aa");
        IFlyweight flyweight2 = FlyweightFactory.getFlyweight("bb");
        flyweight1.operation("a");
        flyweight2.operation("b");
    }

    // Abstract meta role
    interface IFlyweight {
        void operation(String extrinsicState);
    }

    // Specific meta role
    static class ConcreteFlyweight implements IFlyweight {
        private String intrinsicState;

        public ConcreteFlyweight(String intrinsicState) {
            this.intrinsicState = intrinsicState;
        }

        @Override
        public void operation(String extrinsicState) {
            System.out.println("Object address: " + System.identityHashCode(this));
            System.out.println("IntrinsicState: " + this.intrinsicState);
            System.out.println("ExtrinsicState: " + extrinsicState);
        }
    }

    // Xiangyuan factory
    static class FlyweightFactory {
        private static Map<String, IFlyweight> pool = new HashMap<>();

        // Because the internal state is invariant, it is used as the key of cache
        public static IFlyweight getFlyweight(String intrinsicState) {
            if (!pool.containsKey(intrinsicState)) {
                IFlyweight flyweight = new ConcreteFlyweight(intrinsicState);
                pool.put(intrinsicState, flyweight);
            }
            return pool.get(intrinsicState);
        }
    }
}

for instance

Example: we know that it is very troublesome to go home during the new year, because we need to grab a train ticket to go home. When grabbing tickets, we must query whether there is the ticket information we need. Here, we assume that the information of a train includes: departure station, destination station, price and seat category. Now it is required to write a pseudo code for querying train tickets, which can find the information of relevant tickets through the departure station and destination station.

Direct thinking: for example, you need to query the relevant information of train tickets through the departure station and destination station, so we just need to build a train ticket object, and then provide an interface to query the departure station and destination station for customers;
The specific codes are as follows:

class Client {
    public static void main(String[] args) {
        ITicket ticket = TicketFactory.queryTicket("Shenzhen North", "Chaoshan");
        ticket.showInfo("Hard seat");
    }

    interface ITicket {
        void showInfo(String bunk);
    }

    static 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;
        }

        @Override
        public void showInfo(String bunk) {
            this.price = new Random().nextInt(500);
            System.out.println(String.format("%s->%s: %s Price:%s element", this.from, this.to, bunk, this.price));
        }
    }

    static class TicketFactory {
        public static ITicket queryTicket(String from, String to) {
            return new TrainTicket(from, to);
        }
    }
}

Analysis: in the above code, when the client queries, the system directly creates a train ticket object through TicketFactory, but in this way, when a large number of users request the information of the same ticket at a certain moment, the system will create a large number of the train ticket object, and the system memory pressure will increase sharply. In fact, the better way is to cache the ticket object and reuse it for other query requests. Such an object is enough to support thousands of query requests, which has no pressure on memory and can be used Sharing element mode It can solve this problem well;
The specific code is as follows: you only need to change the TicketFactory of the above code and add a caching mechanism:

class Client {
    public static void main(String[] args) {
        ITicket ticket = TicketFactory.queryTicket("Shenzhen North", "Chaoshan");
        ticket.showInfo("Hard seat");
        ticket = TicketFactory.queryTicket("Shenzhen North", "Chaoshan");
        ticket.showInfo("soft seats");
        ticket = TicketFactory.queryTicket("Shenzhen North", "Chaoshan");
        ticket.showInfo("Hard sleeper");
    }
    ...
    ...
    static class TicketFactory {
        private static Map<String, ITicket> sTicketPool = new ConcurrentHashMap<>();

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

The operation results are as follows:

First query, create object ==> Shenzhen North->Chaoshan
 Shenzhen North->Chaoshan: hard seat price: 429 yuan
 Use cache ==> Shenzhen North->Chaoshan
 Shenzhen North->Chaoshan: soft seat price: 321 yuan
 Use cache ==> Shenzhen North->Chaoshan
 Shenzhen North->Chaoshan: hard sleeper price: 481 yuan

It can be seen that except after the first query to create an object, the subsequent query of the same train ticket information uses the cache object, so there is no need to create a new object.

Keywords: Java

Added by Large on Sat, 15 Jan 2022 07:25:47 +0200