享元模式(Flyweight),主要用来减少创建对象的数量,以减少内存占用和提高性能。运用共享技术有效的支持持大量细粒度的对象。
轻,也就是对象使用的内存大小。一般情况下需要大量对象使用 new 进行创建,会消耗大量内存。内部状态,需要外部环境来设置的不能共享的内容称为外部状态。这两种状态是相互独立的,使用 flyweight 模式将一个对象的状态分为内部状态和外部状态,内部状态保持不变,共享不变的部分以达到减少内存占用的目的
享元模式角色:
Flyweight:享元接口,定义具体享元角色需要实现的方法,通过接口传入外部状态
/**
* 享元接口
*/
public interface Flyweight {
/**
* 可以将外部状态作为参数传入方法,但不能改变方法的内部状态
*/
void operator(String extrinsicStatus);
}
ConcreteFlyweight:具体享元对象,可共享内部状态,内部状态在创建时赋予,对象创建之后不再更改,外部状态使用参数传入
/**
* 具体享元对象
*/
public class ConcreteFlyweight implements Flyweight {
/**
* 内部状态
*/
private String internalStatus = null;
public ConcreteFlyweight(String internalStatus) {
this.internalStatus = internalStatus;
}
public ConcreteFlyweight() {
}
@Override
public void operator(String extrinsicStatus) {
System.out.println("internalStatus = " + this.internalStatus);
System.out.println("extrinsicStatus = " + extrinsicStatus);
}
}
UnsharedConcreteFlyweight:不需要共享的 Flyweight 子类,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象
/**
* 不共享的享元对象
*/
public class UnsharedConcreteFlyweight implements Flyweight {
@Override
public void operator(String extrinsicStatus) {
System.out.println("不共享的 extrinsicStatus = " + extrinsicStatus);
}
}
FlyweightFactory:享元工厂角色,负责创建和管理享元角色
import java.util.HashMap;
import java.util.Map;
/**
* 享元工厂
*/
public class FlyweightFactory {
private Map<String, Flyweight> maps = new HashMap<>();
/**
* 单例
*/
private static FlyweightFactory instance = new FlyweightFactory();
public static FlyweightFactory getInstance() {
return instance;
}
/**
* 根据 key 获取享元对象
*/
public Flyweight getFlyweight(String key) {
// 先从缓存中获取对象,对象不存在则创建对象放入容器中
if (!maps.containsKey(key)) {
maps.put(key, new ConcreteFlyweight());
}
return maps.get(key);
}
}
调用方
public class FlyweightClient {
public static void main(String[] args) {
FlyweightFactory factory = FlyweightFactory.getInstance();
Flyweight flyweightA = factory.getFlyweight("A");
flyweightA.operator("A");
Flyweight flyweightB = factory.getFlyweight("B");
flyweightB.operator("B");
UnsharedConcreteFlyweight unsharedConcreteFlyweight = new UnsharedConcreteFlyweight();
unsharedConcreteFlyweight.operator("C");
// internalStatus = null
// extrinsicStatus = A
// internalStatus = null
// extrinsicStatus = B
// 不共享的 extrinsicStatus = C
}
}
比如下棋游戏,一盘棋局可以下很多棋子,常规思维的话每个棋子都是一个对象,每局都会产生很多对象。使用 flyweight 模式的话,棋子的颜色一般是比较少而且不变的,颜色可以作为内部状态,棋子的区别在于它们的位置不同,棋子的坐标可以作为外部状态,这样的话棋子对象最多可以减少到两个实例。
字符串 String 就运用了 flyweight,创建相同的字符串时,会将后创建的字符串的引用指向先创建的字符串,实现字符串再内存中的共享