享元模式
享元模式又称为轻量级模式,享元模式通过资源共享的方式,实现大量细粒度对象的复用,从而减少同类对象的多次创建,减少内存的占用和提高程序的运行速度。
类型:
结构型模式
享元模式的状态:
- 内部状态/内蕴状态(Internal State):内部状态都存储在享元对象的内部,并且不会随着环境的改变而改变,内部状态便是可以共享的状态,一般通过构造方法或者setter方法传入。
- 外部状态/外蕴状态(External State): 外部状态必须由客户端保存,会随着环境的改变而改变,外部状态是不可以共享的,一般享元对象创建之后,根据需要进行参数的传入。并且外部状态的传入不能影响内部状态,他们之间是相互独立的。
享元模式分类:
- 单纯的享元模式:即所有的享元对象都是可以共享的。
- 复合的享元模式:顾名思义,就是将多个单纯的享元对象组合到一起,复合的享元对象是不可以共享的,但是每个部分又是可以共享的单纯的享元对象。
单纯的享元模式:
单纯的享元模式的角色:
- 抽象的享元接口(Flyweight):规定具体实现方法的公共接口
- 具体享元对象(ConcreteFlyweight):实现抽象的享元接口,同时遵守享元对象的一定的规则。
- 享元工厂(FlyweightFactory):负责创建和管理享元对象。
单纯的享元模式关系图:
单纯的享元模式示例:
Flyweight接口:
/**
* Create by zhaihongwei on 2018/3/22
*/
public interface Flyweight {
void operation(String externalState);
}
具体的ConcreteFlyweight对象:
/**
* Create by zhaihongwei on 2018/3/22
*/
public class ConcreteFlyweight implements Flyweight {
private String internalState;
/**
* 构造函数的方式传入内部状态
* @param internalState 内部状态
*/
public ConcreteFlyweight(String internalState) {
this.internalState = internalState;
}
/**
* 外部状态通过普通方法参数的形式传入
* 从而改变具体方法的行为,但是不改变内部状态
* @param externalState 外部状态
*/
@Override
public void operation(String externalState) {
System.out.println("internalState:" + internalState);
System.out.println("externalState:" + externalState);
}
}
FlyweightFactory工厂对象:
/**
* Create by zhaihongwei on 2018/3/22
*/
public class FlyweightFactory {
/**
* 通过HashMap作为容器,保存具体的享元对象
*/
private Map<String,Flyweight> flyweightMap = new HashMap<>();
public Flyweight getFlyweight(String internalState) {
// 先从HashMap容器中寻找有没有
Flyweight flyweight = flyweightMap.get(internalState);
// 这里没有考虑对线程同时访问的情况,具体可以使用单例模式。
if(flyweight == null) {
flyweight = new ConcreteFlyweight(internalState);
flyweightMap.put(internalState,flyweight);
}
return flyweight;
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/22
*/
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight = factory.getFlyweight("first_internalState");
flyweight.operation("first_externalState");
System.out.println(flyweight);
System.out.println("--------------------------------------------");
flyweight.operation("second_externalState");
System.out.println(flyweight);
}
}
测试结果:
internalState:first_internalState
externalState:first_externalState
flyweight.ConcreteFlyweight@606d8acf
--------------------------------------------
internalState:first_internalState
externalState:second_externalState
flyweight.ConcreteFlyweight@606d8acf
可以看出享元对象的内部属性没有改变,并且享元对象没有重新创建,即共享的,但是外部属性是可以变化的。
复合的享元模式
复合的享元模式的角色:
- 抽象的享元接口(Flyweight):规定具体实现方法的公共接口
- 单纯的享元对象(ConcreteFlyweight):实现抽象的享元接口,同时遵守享元对象的一定的规则。
- 复合的享元对象(CompositeConcreteFlyweight):复合的享元对象是不可以共享的,但是每一个部分又是可以共享的。
- 享元工厂(FlyweightFactory):负责创建和管理单纯享元对象和复合享元对象。
复杂的享元模式关系图:
复合的享元模式示例:
Flyweight接口:
/**
* Create by zhaihongwei on 2018/3/22
*/
public interface Flyweight {
void operation(String externalState);
}
CompositeConcreteFlyweight复合享元对象:
/**
* Create by zhaihongwei on 2018/3/22
*/
public class CompositeConcreteFlyweight implements Flyweight{
private Map<String,Flyweight> compositeConcreteFlyweight = new HashMap<>();
/**
* 添加单纯的享元对象
* @param internalState 内部状态
* @param flyweight 单纯的享元对象
*/
public void putFlyweight(String internalState,Flyweight flyweight) {
compositeConcreteFlyweight.put(internalState,flyweight);
}
/**
* 获取复合享元对象中的一个单纯的享元对象
* @param internalState
* @return
*/
public Flyweight getFlyweight(String internalState) {
return compositeConcreteFlyweight.get(internalState);
}
@Override
public void operation(String externalState) {
// 遍历复合的享元对象中包含的每个单纯的享元对象。
for (String internalState : compositeConcreteFlyweight.keySet()) {
Flyweight flyweight = compositeConcreteFlyweight.get(internalState);
flyweight.operation(externalState);
}
}
}
复合享元工厂:其中包含了单纯享元对象和复合享元对象的获取方法
/**
* Create by zhaihongwei on 2018/3/22
*/
public class FlyweightFactory {
/**
* 通过HashMap作为容器,保存具体的享元对象
*/
private Map<String,Flyweight> flyweightMap = new HashMap<>();
/**
* 获取单纯的享元对象
* @param internalState 内部状态
* @return
*/
public Flyweight getFlyweight(String internalState) {
// 先从HashMap容器中寻找有没有
Flyweight flyweight = flyweightMap.get(internalState);
// 这里没有考虑对线程同时访问的情况,具体可以使用单例模式。
if(flyweight == null) {
flyweight = new ConcreteFlyweight(internalState);
flyweightMap.put(internalState,flyweight);
}
return flyweight;
}
/**
* 获取复合的享元对象
* @param internalStates 多个单纯的享元对象的内部状态
* @return
*/
public Flyweight getCompositeFlyweight(List<String> internalStates) {
CompositeConcreteFlyweight ccFlyweight = new CompositeConcreteFlyweight();
for (String internalState : internalStates) {
ccFlyweight.putFlyweight(internalState,getFlyweight(internalState));
}
return ccFlyweight;
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/22
*/
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
List<String> internalStates = new ArrayList<>();
internalStates.add("first_internalState");
internalStates.add("second_internalState");
CompositeConcreteFlyweight compositeFlyweightA = (CompositeConcreteFlyweight) factory.getCompositeFlyweight(internalStates);
CompositeConcreteFlyweight compositeFlyweightB = (CompositeConcreteFlyweight) factory.getCompositeFlyweight(internalStates);
System.out.println("compositeFlyweightA和compositeFlyweightB是和可以共享的嘛?" + (compositeFlyweightA==compositeFlyweightB));
System.out.println("-----------------------------------------------");
System.out.println("compositeFlyweightA中的first_internalState和compositeFlyweightB中的first_internalState是可以共享的嘛?" + (compositeFlyweightA.getFlyweight(internalStates.get(0))==compositeFlyweightB.getFlyweight(internalStates.get(0))));
}
}
测试结果:
compositeFlyweightA和compositeFlyweightB是和可以共享的嘛?false
-----------------------------------------------
compositeFlyweightA中的first_internalState和compositeFlyweightB中的first_internalState是可以共享的嘛?true
从测试结果可以得出,复合的享元对象是不可以共享的,但是复合享元对象中的每一个单纯的享元对象的可以共享的。
个人感想:
至此7中结构型模式学完,下面将进入11种行为型模式的学习,加油!!!