Java Design Patterns--Flyweight Pattern

1 Flyweight Pattern Flyweight Pattern

Purpose: To reduce the number of created objects, reduce memory usage and improve performance;
Implementation: Use the unique identification code to judge, if there is one in the memory, return the object identified by the unique identification code.

1. Use sharing technology to effectively support the reuse of a large number of fine-grained objects; the system only uses a small number of objects, and these objects are very similar, and the state changes are small, and multiple reuse of objects can be realized. If no matching object is found , then a new object is created;
2. Flyweight mode efficiently supports the reuse of a large number of fine-grained objects in a shared way. The key to the sharing of Flyweight objects is to distinguish between the internal state (Intrinsic State) and the external state (Extrinsic State) .

2 Implementation

Code scenario: Generate a thread pool with a predefined thread name. If the thread obtained by the client exists, the thread in the thread pool will be returned. If it does not exist, a new thread will be created.

2.1 Code Implementation

Abstract flyweight class: AbstractThread

public abstract class AbstractThread {
    // 线程内部状态
    protected String threadName;

    public AbstractThread(String threadName) {
        this.threadName = threadName;
    }

    // 线程外部状态
    public void threadStatus(String threadStatus) {
        System.out.println(threadName + "当前外部状态为:" + threadStatus);
    }

    public abstract void excute();
}

Specific flyweight class: ThreadA

public class ThreadA extends AbstractThread {

    public ThreadA(String threadName) {
        super(threadName);
    }

    @Override
    public void excute() {
        System.out.println("线程[" + threadName + "]开始执行任务~");
    }

}

Specific flyweight class: ThreadB

public class ThreadB extends AbstractThread {

    public ThreadB(String threadName) {
        super(threadName);
    }

    @Override
    public void excute() {
        System.out.println("线程[" + threadName + "]开始执行任务~");
    }

}

Specific flyweight class: ThreadNew is added when it does not match

public class ThreadNew extends AbstractThread {

    public ThreadNew(String threadName) {
        super(threadName);
    }

    @Override
    public void excute() {
        System.out.println("线程[" + threadName + "]开始执行任务~");
    }

}

Flyweight factory class: ThreadFactory

public class ThreadFactory {
    private static ThreadFactory threadFactory = new ThreadFactory();
    private Map<String, AbstractThread> threadMap = new HashMap<String, AbstractThread>();

    private ThreadFactory() {
        AbstractThread threadA = new ThreadA("A");
        AbstractThread threadB = new ThreadB("B");
        threadMap.put("A", threadA);
        threadMap.put("B", threadB);

    }

    public static ThreadFactory getThreadFactory() {
        return threadFactory;
    }

    public AbstractThread getThread(String threadName) {
        // 如果想要获取的线程享元池中存在 则从享元池中获取
        if (threadMap.containsKey(threadName)) {
            return threadMap.get(threadName);
        }
        // 如果想要获取的线程享元池中不存在 则new一个
        else {
            ThreadNew threadNew = new ThreadNew(threadName);
            threadMap.put(threadName, threadNew);
            return threadNew;
        }

    }
}

2.2 Involving roles

The flyweight pattern structure diagram includes the following roles:

Flyweight (abstract flyweight class) : usually an interface or abstract class, which declares the public methods of the concrete flyweight class in the abstract flyweight class. These methods can provide the internal data (internal state) of the flyweight object to the outside world, and at the same time External data (external state) can also be set through these methods.

ConcreteFlyweight (concrete flyweight class) : It implements an abstract flyweight class, and its instance is called a flyweight object; it provides storage space for the internal state in the concrete flyweight class. Usually, we can design specific flyweight classes in combination with the singleton pattern, and provide a unique flyweight object for each specific flyweight class.

UnsharedConcreteFlyweight (non-shared concrete flyweight class) : Not all subclasses of abstract flyweight classes need to be shared, and subclasses that cannot be shared can be designed as non-shared concrete flyweight classes; when a non-shared concrete flyweight class is required Objects of a class can be created directly by instantiation.
FlyweightFactory (Flyweight Factory class) : Flyweight Factory class is used to create and manage Flyweight objects. It is programmed for abstract Flyweight classes and stores various types of specific Flyweight objects in a Flyweight pool. Flyweight pools generally It is designed to store a collection of "key-value pairs" (it can also be other types of collections), and can be designed in conjunction with the factory pattern; when a user requests a specific flyweight object, the flyweight factory provides a collection that has been stored in the flyweight pool. Created instance or creates a new instance (if it does not exist), returns the newly created instance and stores it in the flyweight pool.

A brief introduction to Flyweight's internal state and external state:
(1) Internal state is a state that is stored inside the Flyweight object and will not change with the environment, and the internal state can be shared. For example, the content of the character will not change with the change of the external environment. No matter in any environment, the character "a" is always "a" and will not become "b".

(2) The external state is a state that changes with the environment and cannot be shared. The external state of the flyweight object is usually saved by the client, and is passed into the flyweight object when it needs to be used after the flyweight object is created. An external state is independent of another external state. For example, the color of characters can have different colors in different places. For example, some "a" is red, some "a" is green, and the size of the characters is the same. Some "a" is a four-point word. Moreover, the color and size of characters are two independent external states, which can be changed independently without affecting each other. The client can inject the external state into the flyweight object when using it.


Because of the distinction between the internal state and the external state, we can store objects with the same internal state in the flyweight pool. The objects in the flyweight pool can be shared, and the objects are taken out of the flyweight pool when needed. , to achieve object reuse. By injecting different external states into the fetched object, you can get a series of similar objects that actually only have one copy in memory.

2.3 call

caller:

public class Client {
    public static void main(String[] args) {
        // 获取享元工厂
        ThreadFactory threadFactory = ThreadFactory.getThreadFactory();
        // 获取共享元素
        AbstractThread thread1 = threadFactory.getThread("A");
        AbstractThread thread2 = threadFactory.getThread("B");
        // 获取新元素
        AbstractThread thread3 = threadFactory.getThread("C");
        // 线程执行任务
        thread1.excute();
        thread2.excute();
        thread3.excute();

        AbstractThread thread4 = threadFactory.getThread("A");
        // thread1和thread4获取的是同一个实例
        if (thread1 == thread4) {
            System.out.println("thread1 == thread4");
        }
    }
}

result:

线程[A]开始执行任务~
线程[B]开始执行任务~
线程[C]开始执行任务~
thread1 == thread4

Code address: click to jump

References:
[1] Graphical Design Patterns/(Japanese) Hiroshi Yuki; translated by Yang Wenxuan. – Beijing: People’s Posts and Telecommunications Press, 2017.1.
[ 2 ] Wikipedia Design
Patterns [ 3 ] Geek Academy WIKI – Design Patterns .
[ 4 ] Rookie Tutorial – Design Patterns .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325988908&siteId=291194637