Writing in the front
- Take notes on learning design patterns
- Improve flexibility in the use of design patterns
Learning to address
https://www.bilibili.com/vide…
https://www.bilibili.com/vide…
Refer to the article
http://c.biancheng.net/view/1…
Project source https://gitee.com/zhuang-kang/DesignPattern
14, enjoy the yuan mode
14.1 Definition and Characteristics of Entrance Pattern
The definition of Flyweight pattern: it uses sharing technology to effectively support the reuse of a large number of fine-grained objects. By sharing existing objects, it can greatly reduce the number of objects to be created and avoid the overhead of a large number of similar classes, so as to improve the utilization of system resources.
The main advantage of the shared element pattern is that only one copy of the same object is kept, which reduces the number of objects in the system and thus reduces the pressure on memory imposed by fine-grained objects in the system.
Its main disadvantages are:
- To make objects shareable, you need to externalize some of the states that cannot be shared, which increases the complexity of the program.
- Reading the external state of the entry schema makes the runtime slightly longer.
14.2 Structure and Implementation of Endowment Pattern
14.2.1 Structure of Endowment Mode
There are two states in Flyweight mode:
- Internal state, that is, shareable parts that do not change as the environment changes.
- External state refers to the part that changes as the environment changes and cannot be shared. The key to realize the Endowment Pattern is to distinguish the two states in the application and externalize the external states.
The main roles of enjoy yuan mode are as follows:
- Abstract metaclass role (Flyweight) : Usually an interface or abstract class that declares methods common to a specific metaclass that provide the internal data (internal state) of a metaclass object to the outside world, as well as the external data (external state) that can be set by these methods.
- Concrete Flyweight role: It implements the abstract Flyweight class, known as the Flyweight object; A storage space is provided for internal state in a concrete member class. Usually we can combine the singleton pattern to design specific metaclass, and provide a unique metaclass object for each specific metaclass.
- Unsharable Flyweight roles: Not all subclasses of abstract metaclasses need to be shared, and subclasses that cannot be shared can be designed as non-shared concrete metaclasses. When an object that is not a shared specific enjoyment metaclass is needed, it can be created directly through instantiation.
- Flyweight Factory Roles: Responsible for creating and managing Flyweight Roles. When a customer object requests a premium object, the premium factory checks whether there is a premium object in the system that meets the requirements, and provides it to the customer if there is. If it does not exist, a new enjoyment object is created.
14.2.1 Code implementation
Relationship between the class diagram
IBox defines different shapes
package com.zhuang.flyweight; /** * @ClassName iBox * @Description iBox * @Date 2021/3/25 15:33 * @Created by Dell */ public class iBox extends AbstractBox { @Override public String getShape() { return "I"; }}
LBox defines different shapes
package com.zhuang.flyweight; /** * @ClassName iBox * @Description * @Date 2021/3/25 15:33 * @Created by Dell */ public class LBox extends AbstractBox { @Override public String getShape() { return "L"; }}
OBox defines different shapes
package com.zhuang.flyweight; /** * @className iBox * @description * @date 2021/3/25 15:33 * @Created by Dell */ public class oBox extends AbstractBox { @Override public String getShape() { return "O"; }}
BoxFactory provides a factory class for managing subclass objects (i.e., AbstractBox subclass objects). Only one of the factory objects is required, so the singleton pattern can be used. And give the factory class a method to get the shape
package com.zhuang.flyweight; import java.util.HashMap; /** * @ClassName BoxFactory * @Description * @Date 2021/3/25 15:33 * @Created by Dell */ public class BoxFactory { private HashMap<String, AbstractBox> map; Private BoxFactory() {map = new HashMap<String, AbstractBox>(); IBox iBox = new IBox(); LBox lBox = new LBox(); OBox oBox = new OBox(); map.put("I", iBox); map.put("L", lBox); map.put("O", oBox); } public static BoxFactory getInstance() {return singletonHolder.instance; } private static class SingletonHolder { private static final BoxFactory INSTANCE = new BoxFactory(); } public abstractBox getShape(String name) {return map.get(name); }}
AbstractBox extracts an AbstractBox from these shapes to define common attributes and behaviors
package com.zhuang.flyweight; /** * @classname AbstractBox * @description * @date 2021/3/25 15:32 * @created by dell */ public abstract Class abstractBox {public abstract String getShape(); public abstract String getShape(); Public void display(String color) {System.out.println(" + this.getShape() + color: "+ color); }}
14.3 Application scenarios of Xiangyuan mode
When many places in the system need the same set of information, these information can be encapsulated into an object, and then the object is cached. In this way, an object can be provided to more places that need to be used, avoiding the creation of a large number of the same object, and reducing the consumption of a large amount of memory space.
Endowment pattern is actually an improved mechanism of the factory method pattern. Endowment pattern also requires the creation of an object or a group of objects, and is generated through the factory method pattern, but the Endowment pattern for the factory method pattern to increase the caching function.
The structure and characteristics of enjoy element pattern are analyzed in the front, and the following application scenarios are analyzed for its application. The sharing pattern saves memory space by reducing the number of objects in memory, so the following scenarios are suitable for the sharing pattern.
- There are a large number of identical or similar objects in the system, which consume a large amount of memory resources.
- Most objects can be grouped according to their internal state, and the different parts can be externalized so that each group only holds one internal state.
- Since the enjoyment schema requires the maintenance of an additional data structure that holds the enjoyment schema, it should be worthwhile to use the enjoyment schema when there are enough instances of the enjoyment schema
14.4 JDK source code parsing
The Integer class uses the Entity pattern. Let’s start with the following example:
public class Demo { public static void main(String[] args) { Integer i1 = 127; Integer i2 = 127; System.out.println(" Are I1 and I2 objects the same object? ") + (i1 == i2)); Integer i3 = 128; Integer i4 = 128; System.out.println(" Are I3 and I4 objects the same object? ") + (i3 == i4)); }}
The result is true false
Why does the first statement print true and the second false? To decompile with decompilation software, the code is as follows:
public class Demo { public static void main(String[] args) { Integer i1 = Integer.valueOf((int)127); Integer i2 Integer.valueOf((int)127); System.out.println((String)new StringBuilder().append((String)"i1\u548ci2\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f").append((b oolean)(i1 == i2)).toString()); Integer i3 = Integer.valueOf((int)128); Integer i4 = Integer.valueOf((int)128); System.out.println((String)new StringBuilder().append((String)"i3\u548ci4\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f").append((b oolean)(i3 == i4)).toString()); }}
As you can see from the above code, valueOf() is used underneath the operation to assign primitive data directly to a variable of type Integer, so you just need to look at this method
public final class Integer extends Number implements Comparable<Integer> { public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { 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) { } } 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; } private IntegerCache() {} } }
You can see that by default Integer objects that are counted between -128 and 127 are created and cached. When valueOf is called, the index is evaluated and returned from the cache if the argument is between -128 and 127, otherwise a new Integer object is created.
Write in the last
- If my article is useful to you, please click 👍, thank you!
- Let me know in the comments section if you have any questions! 💪