Sharing element mode
Object oriented technology can solve some flexibility and 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. Xiangyuan mode was officially born to solve this kind of problem.
Sharing element mode (Flyweight Pattern), also known as lightweight pattern, is an implementation of object pool. Similar to thread pool, thread pool can avoid constantly creating and destroying multiple objects and consuming performance. It provides a way to reduce the number of objects and improve the object structure required by applications. Its purpose is to share fine-grained objects and centralize multiple accesses to the same object, which is no better than each other Visitors create a single object once to reduce memory consumption, which belongs to structural mode. Shared meta 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 and memory are reduced.
The essence of meta sharing mode is to cache shared objects and reduce memory consumption.
UML class diagram:
There are three roles involved in the sharing mode:
Abstract shared meta role (Flyweight): shared meta object abstract base class or interface. Colleagues define 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 state processing of the role should be independent of the environment. There can be no operation to change the internal state and modify the external state;
FlyweightFactory: responsible for managing the shared object pool and creating shared objects.
Application scenarios of meta mode
The meta sharing mode is actually an improved mechanism of the factory mode. The meta sharing mode also requires the creation of one or a group of objects, and the objects are generated through the factory method, but the caching function is added to the factory method in the meta sharing mode. There are mainly the following application scenarios:
- It is often used in the development of the underlying system in order to solve the system performance problems.
- The system has a large number of similar objects and needs a buffer pool.
Using shared element mode to realize shared pool service
Implement a train ticket swiping software. It is required to query the relevant information of train tickets through the departure station and destination station. As long as the train ticket object is provided, and then an interface for querying the departure station and destination station is provided to the customer for query, the ITicket interface is created:
public interface ITicket { void showInfo(String bunk); }
Create TrainTicket
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; } 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)); } }
Finally create
public static class TicketFactory { public static ITicket queryTicket(String from, String to) { return new TrainTicket(from, to); } }
Client code:
public static void main(String[] args) { ITicket ticket = TicketFactory.queryTicket("West Beijing", "Changsha"); ticket.showInfo("Hard seat"); }
After analyzing the above code, when the client queries, the system directly creates a train ticket object through TicketFactory. However, in this way, if a large number of users request the same ticket information at a certain moment, the system will create a large number of train ticket objects, and the system memory pressure will increase sharply. 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 and has no pressure on memory. Using the sharing mode can solve this problem. Continue to optimize the code and increase the cache mechanism:
class TicketFactory { private static Map<String, ITicket> sTicketPool = new ConcurrentHashMap<String,ITicket>(); 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; } }
public static void main(String[] args) { ITicket ticket = TicketFactory.queryTicket("West Beijing", "Changsha"); ticket.showInfo("Hard seat"); ticket = TicketFactory.queryTicket("West Beijing", "Changsha"); ticket.showInfo("soft seats"); ticket = TicketFactory.queryTicket("West Beijing", "Changsha"); ticket.showInfo("Hard sleeper"); }
You can see that after the object is created in the first query, the subsequent query of ticket information of the same train number uses cache objects. There is no need to create a new object. Take a look at the class structure diagram:
Looking at this kind of diagram, don't you think this is the registered singleton mode? This is the registered singleton mode. Although the structure is similar, the focus of the meta pattern is on the structure, not on the creation of objects. Take another look at the source code in several jdks.
For example, the commonly used database Connection pool, because the main performance consumption is when we use the Connection object. When we re-establish and close the Connection, in order to improve the performance of the Connection during the call, we create a cache for the Connection object before the call, take values from the cache when we use it, and put it back after use, so as to achieve the purpose of resource reuse.
public class ConnectionPool { private Vector<Connection> pool; private String url = "jdbc:mysql://localhost:3306/test"; private String username = "root"; private String password = "root"; private String driverClassName = "com.mysql.jdbc.Driver"; private int poolSize = 100; public ConnectionPool() { pool = new Vector<Connection>(poolSize); try{ Class.forName(driverClassName); for (int i = 0; i < poolSize; i++) { Connection conn = DriverManager.getConnection(url,username,password); pool.add(conn); } }catch (Exception e){ e.printStackTrace(); } } public synchronized Connection getConnection(){ if(pool.size() > 0){ Connection conn = pool.get(0); pool.remove(conn); return conn; } return null; } public synchronized void release(Connection conn){ pool.add(conn); } }
Such connection pools are widely used in open source frameworks to effectively improve the underlying performance.
Application of meta pattern in source code
Meta mode in String
Java defines the String class as final (immutable). Strings in the JVM are generally saved in the String constant pool. Java will ensure that there is only one copy of a String in the constant pool. Before JDK6.0, the String constant pool was located in the constant pool and in the permanent generation. In JDK7.0, the JVM takes it out of the permanent generation and places it in the heap.
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==s9);//false System.out.println(s4==s5);//false System.out.println(s1==s6);//true System.out.println(s1==s9);//false }
Meta mode in Integer
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 }
I'll write a separate article on String and Integer to answer them in detail. When I didn't understand this part of the content before, I also spared a lot of circles. After learning the enjoy yuan mode, I feel that my thinking is clear.
Meta mode in Apache Commons Pool
The basic idea of Object Pool is to save used objects and wait for the next time such objects are needed, and then take them out for reuse, so as to reduce the overhead caused by frequent object creation to a certain extent. Objects used as "containers" for saving objects are called "object pools".
Apache Commons Pool implements the function of object pool. The generation, destruction, activation, passivation and other operations of objects and their state transformation are defined, and several default object pool implementations are provided. There are several important objects:
PooledObject: used to encapsulate objects (such as threads, database connections, TCP connections) and wrap them into objects that can be managed by the pool.
PooledObjectFactory: defines some methods to operate the PooledObject instance life cycle. PooledObject must implement thread safety.
ObjectPool: ObjectPool is responsible for managing pooledobjects, such as lending objects, returning objects, verifying objects, how many active objects there are and how many free objects there are.
We won't analyze the specific source code here.
Internal and external states of meta mode
The definition of shared meta pattern puts forward two requirements for us: fine granularity and shared objects. Because fine-grained objects are required, it is inevitable that there are many objects with similar properties. At this time, 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, which is stored in the shared meta object and will not change with the change of the environment; External state refers to a mark on which an object depends. It is a state that changes with the environment and cannot be shared.
For example, the connection object in the connection pool, the user name and password saved in the connection object will not be changed at will. These are internal states. When each link is to be recycled, we need to mark it as available, which is the external state.
Advantages and disadvantages of sharing mode
advantage:
- Reduce the creation of objects, reduce the number of objects in memory, reduce the memory of the system and improve efficiency;
- Reduce the occupation of resources other than memory.
Disadvantages:
- Pay attention to internal and external states and thread safety issues
- Complicate the logic of the system and program
The state of being changed and not shared.
For example, the connection object in the connection pool, the user name and password saved in the connection object will not be changed at will. These are internal states. When each link is to be recycled, we need to mark it as available, which is the external state.
Advantages and disadvantages of sharing mode
advantage:
- Reduce the creation of objects, reduce the number of objects in memory, reduce the memory of the system and improve efficiency;
- Reduce the occupation of resources other than memory.
Disadvantages:
- Pay attention to internal and external states and thread safety issues
- Complicate the logic of the system and program