享元模式
什么是享元模式
享元模式(Flyweight Pattern)是一种对象结构型设计模式,用于减少创建对象的数量,以减少内存占用和提高系统性能。它通过共享已经存在的对象来避免创建大量相似的对象,从而降低内存消耗。
在享元模式中,通常会有一些细粒度的对象,它们具有一些共同的属性,但是某些属性可能会变化。
- 优点
- 减少对象数量:通过共享对象,可以显著减少系统中对象的数量,从而节省内存空间。
- 提高性能:由于减少了对象的创建和销毁,可以提高系统的性能。
- 缺点
- 增加系统复杂性:引入享元模式可能会增加系统的复杂性,特别是当处理内在状态和外在状态的分离时。
- 可能不适用于所有场景:不是所有情况都适合使用享元模式,例如当对象的状态变化非常频繁时,共享对象可能不是最佳选择。
核心
- 享元模式以共享的方式高效的支持大量细粒度对象的复用。
- 享元对象能做到共享的关键是区分了内部状态和外部状态。
- 内部状态:可以共享,不会岁环境变化发生改变
- 外部状态:不可以共享,会随环境变化二改变
享元模式的实现
- 抽象享元类(Flyweight):通常是一个接口或者抽象类,声明公共的方法,这些方法可以想外界提供对象的内部状态及设置外部状态
- 具体享元类(ConcreteFlyweight):为内部状态提供成员变量进行存储
- 非共享享元类(UnsharedConcreteFlyweight):不能为共享的子类可以设计成非共享享元类
- 享元工厂(FlyweightFactory):创建并管理享元对象享元池一般设计成键值对
案例
对于围棋,棋子进行简单可以划分:
内部状态:颜色
外部状态:棋盘坐标
UML
实现步骤:
-
定义外部状态:地址Address
-
定义享元接口:提供操作外部状态的接口,通过传入地址获取外部状态地址的信息
-
定义享元接口的实现(围棋)
- 通过属性设置内部状态,并提供内部状态的设置及调用方法(这里只提供了设置方法)
- 通过实现享元接口,传入外部状态调用外部状态方法或获取外部状态属性
-
享元工厂
- 定义享元池(通常以键值对形式缓存),用于缓存共享内部状态(该方法只适用单线程,多线程需要进行优化)
- 提供获取内部状态的方法,如果享元池中已存在,则享元池中对象,否则新建一个对象并设置到享元池中
代码实现
Address.java
// 定义外部状态
public class Address {
private int x;
private int y;
public Address(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Flyweight.java
// 享元接口:
// * 提供操作外部状态的接口
public interface Flyweight {
// 获取棋子信息:
// * 通过传入地址获取外部状态地址的信息
void getInfo(Address address);
}
ChessPieces.java
//定义享元接口的实现:
// 围棋:
// 通过属性设置内部状态,并提供内部状态的设置及调用方法(这里只提供了设置方法)、
// 通过实现享元接口,传入外部状态调用外部状态方法或获取外部状态属性
public class ChessPieces implements Flyweight{
private String color;
public ChessPieces(String color) {
this.color = color;
}
@Override
public void getInfo(Address address) {
System.out.printf("颜色:%s,坐标:x=%s,y=%s%n",color,address.getX(),address.getY());
}
}
FlyweightFactory.java
import java.util.HashMap;
import java.util.Map;
// 享元工厂
// * 定义享元池(通常以键值对形式缓存),用于缓存共享内部状态(该方法只适用单线程,多线程需要进行优化)
// * 提供获取内部状态的方法,如果享元池中已存在,则享元池中对象,否则新建一个对象并设置到享元池中
public class FlyweightFactory {
// 定义享元池
private Map<String, Flyweight> mapPool = new HashMap<String, Flyweight>();
// 提供获取内部状态的方法
public Flyweight getChessPieces(String key){
Flyweight flyweight = mapPool.get(key);
if(flyweight == null){
flyweight = new ChessPieces(key);
mapPool.put(key, flyweight);
}
return flyweight;
}
}
TestClient.java
public class TestClient {
public static void main(String[] args) {
FlyweightFactory flyweightFactory = new FlyweightFactory();
Flyweight chessPieces = flyweightFactory.getChessPieces("白色");
chessPieces.getInfo(new Address(1,2));
}
}
执行结果:
gitee源码
git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git