( 十四 )、 设计模式 之 享元模式(Flyweight)
( 十四 )、 设计模式 之 享元模式(Flyweight)
1、简介
定义:享元模式(Flyweight Pattern)是一种对象结构型模式,主要用于减少创建对象的数量,以减少内存占用和提高性能。享元模式存储这些共享实例的地方称为享元池(Flyweight Pool),可以避免频繁的创建销毁对象,大幅度减少需要创建的对象数量,避免大量相似类的开销,从而提高系统资源的利用率。一般和单例模式配合使用,将享元工厂声明为一个单例类来池化享元对象。享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式。
享元模式的核心思想
分离出不变部分与可变部分,通过共享不变部分来减少对象的创建,从而降低内存消耗和提高性能。这种模式的实现方式是通过将对象的状态分为内部状态和外部状态,内部状态是对象不可变的共享部分,而外部状态是可以改变的独立部分。当多个客户端请求同一个享元对象时,它们实际上共享的是同一个对象,这样就避免了重复创建相同的对象,从而节省了内存空间。同时,享元模式还通过工厂模式来实现对象的创建和管理,通过缓存等技术手段来提高对象的复用效率。
2、享元模式的结构
- 抽象享元角色(AbstractFlyWeight):为具体享元角色规定了必须实现的方法,在Java中可以是抽象类,也可以是接口。
- 具体享元角色(ConcreteFlyWeight):实现抽象角色定义的方法。
- 享元工厂角色(FlyWeightFactory):生成AbstractFlyWeight角色的工厂,在工厂中生成的AbstractFlyWeight角色可以实现共享实例。享元工厂提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
- 客户端角色(Client):使用FlyWeightFactory来生成AbstractFlyWeight角色。
3、实现
/**
* @Author
* @ClassName AbstractFlyWeight
* @Description 抽象享元角色(可以是接口, 也可以是抽象类)
* @Date 2023/12/16 14:46
* @Version 1.0
*/
public interface AbstractFlyWeight {
}
/**
* @Author
* @ClassName ConcreteFlyWeight
* @Description 具体享元角色
* @Date 2023/12/16 14:47
* @Version 1.0
*/
public class ConcreteFlyWeight implements AbstractFlyWeight {
}
/**
* @Author
* @ClassName FlyWeightFactory
* @Description 享元工厂角色
* @Date 2023/12/16 14:48
* @Version 1.0
*/
public class FlyWeightFactory {
/**
* 持有一个对象缓冲池
*/
private static final ConcurrentHashMap<String, AbstractFlyWeight> OBJECT_MAP = new ConcurrentHashMap<>();
/**
* 方便测试
*/
// static {
// OBJECT_MAP.put("ConcreteFlyWeight", new ConcreteFlyWeight());
// }
public static AbstractFlyWeight getObjects(Class<?> cls) throws InstantiationException,
IllegalAccessException {
AbstractFlyWeight obj = OBJECT_MAP.get(cls.getSimpleName());
if (obj == null) {
obj = (AbstractFlyWeight) cls.newInstance();
OBJECT_MAP.put(cls.getSimpleName(), obj);
}
return obj;
}
}
/**
* @Author
* @ClassName Client
* @Description 客户端角色
* @Date 2023/12/16 14:56
* @Version 1.0
*/
public class Client {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
FlyWeightFactory.getObjects(ConcreteFlyWeight.class);
}
}
4、享元模式适用场景
- 需要大量使用相同或相似对象的场景。享元模式通过共享对象来避免重复创建相同的对象,从而降低内存消耗和提高系统性能。
- 线程池是另一种常见的享元模式应用场景。线程池可以避免频繁地创建和销毁线程对象,从而提高系统的效率和性能。
5、享元模式与单例模式的区别
目的不同:单例模式的目的是确保一个类仅有一个实例,而享元模式的目的是通过共享对象来减少内存消耗,提高程序的性能。
6、优缺点
优点: 大大减少对象的创建,降低系统的内存,使效率提高。
缺点: 提高了系统的复杂度,需要分离出外部状态和内部状态,否则可能会引起线程安全问题。