享元模式
享元模式:运用共享技术,有效地支持大量细粒度的对象的复用。
设计思路分析
内部状态与外部状态
- 内部状态(Intrinsic State):最细粒度的要求共享的内容。
- 外部状态(Extrinsic State):由外部环境设置且不可共享的内容。
特点
- 内部状态与外部状态相互独立,不能相互影响。
- 设置不同的外部状态,可以使用共享对象展现不同特征,从而达到共享内部状态的目的。
- 内部状态为了方便共享,所以应该为较小的细粒度对象,以便共享。
总结
- 享元模式本质上是分离变化与不变,共享不变。
享元模式类
模式类结构图
模式的结构说明
- 抽象享元(Flyweight)角色: 享元接口或抽象类,定义所有享元对象的方法,且接受并作用于外部状态。
- 具体享元(ConcreteFlyweight)角色:具体的享元对象,必须是可共享的细粒度对象,为其内部状态分配内存。
- 享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。
- 非共享享元角色(UnsharedConcreteFlyweight):非共享的享元对象,同样实现了Flyweight 但不共享,是为了其特定需要对具体享元对象的组合,其内部维护享元对象集合,该集合内部所有享元对象共用一个外部状态。
单纯享元对象与复合享元对象
- 单纯享元对象:最小粒度的复用对象,内部状态为其共享的部分。
- 复合享元对象: 复合享元对象是对享元对象以统一的外部状态进行包装的另类不可共享的享元对象。
Demo
Flyweight.java
package com.frank.designMode.flyweight.demo;
/**
* @Description: 抽象享元角色-Flyweight
* @Author: Frank.Liu
* @Date:25/08/2019
*/
public interface Flyweight {
void operation(String extrinsicState);
}
FlyweightFactory.java
package com.frank.designMode.flyweight.demo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description: 享元工厂-Flyweight
* @Author: Frank.Liu
* @Date:25/08/2019
*/
public class FlyweightFactory {
// 具体享元对象集合
private Map<String,Flyweight> flyweightMap = new HashMap<>();
private static FlyweightFactory flyweightFactory =new FlyweightFactory();
// 私有化构造方法
private FlyweightFactory(){
}
// 获取享元工厂对象
public static FlyweightFactory getFlyweightFactory(){
return flyweightFactory;
}
/**
* 获取享元对象
* @param intrinsicState
* @return
*/
public Flyweight getFlyweight(String intrinsicState){
Flyweight flyweight = flyweightMap.get(intrinsicState);
if(flyweight == null){
flyweight = new ConcreteFlyweight(intrinsicState);
flyweightMap.put(intrinsicState,flyweight);
}
return flyweight;
}
/**
* 获取复合享元对象
* @param intrinsicStates
* @return
*/
public UnsharedConcreteFlyweight getUnsharedFlyweight(List<String> intrinsicStates) {
UnsharedConcreteFlyweight unsharedFlyweight = new UnsharedConcreteFlyweight();
for (String intrinsicState : intrinsicStates) {
unsharedFlyweight.add(intrinsicState, getFlyweight(intrinsicState));
}
return unsharedFlyweight;
}
public Map<String,Flyweight> getFlyweightMap(){
return this.flyweightMap;
}
}
ConcreteFlyweight.java
package com.frank.designMode.flyweight.demo;
/**
* @Description: 具体享元角色-ConcreteFlyweight
* @Author: Frank.Liu
* @Date:25/08/2019
*/
public class ConcreteFlyweight implements Flyweight{
private String intrinsicState = null;
public ConcreteFlyweight(String intrinsicState){
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String extrinsicState) {
System.out.println();
System.out.println("内部状态:" + intrinsicState);
System.out.println("外部状态:" + extrinsicState);
System.out.println("=========================");
}
@Override
public String toString() {
return this.intrinsicState;
}
}
UnsharedConcreteFlyweight.java
package com.frank.designMode.flyweight.demo;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: 复合享元角色-ConcreteFlyweight
* @Author: Frank.Liu
* @Date:25/08/2019
*/
public class UnsharedConcreteFlyweight implements Flyweight{
//用来登记和存储已经创建过的享元对象
private Map<String, Flyweight> flyweightMap = new HashMap<>();
// 该享元对象共同歪蕴状态
private String extrinsicState = null;
// 增加享元对象到集合中
public void add(String intrinsicState, Flyweight flyweight) {
flyweightMap.put(intrinsicState, flyweight);
}
@Override
public void operation(String extrinsicState) {
this.extrinsicState = extrinsicState;
}
public void getFlyweight(String intrinsicState){
Flyweight flyweight=flyweightMap.get(intrinsicState);
if(null!=flyweight){
flyweight.operation(extrinsicState);
}else{
System.out.println();
System.out.println(extrinsicState+"未点过:"+intrinsicState);
System.out.println("-------------------------");
}
}
public Map<String, Flyweight> getFlyweightMap() {
return flyweightMap;
}
}
MenumClient.java
package com.frank.designMode.flyweight.demo;
import java.util.ArrayList;
import java.util.List;
public class MenumClient {
public static void main(String[] args) {
List<String> intrinsicStates = new ArrayList<>();
intrinsicStates.add("木须肉");
intrinsicStates.add("地三鲜");
intrinsicStates.add("孜然牛肉");
FlyweightFactory flyFactory =FlyweightFactory.getFlyweightFactory();
UnsharedConcreteFlyweight unsharedFlyweight1 = flyFactory.getUnsharedFlyweight(intrinsicStates);
UnsharedConcreteFlyweight unsharedFlyweight2 = flyFactory.getUnsharedFlyweight(intrinsicStates);
System.out.println("复合享元对象是否可以共享:" + (unsharedFlyweight1 == unsharedFlyweight2));
unsharedFlyweight1.operation("一号桌");
unsharedFlyweight2.operation("五号桌");
//开始给一号桌上菜了
unsharedFlyweight1.getFlyweight("木须肉");
unsharedFlyweight1.getFlyweight("地三鲜");
unsharedFlyweight1.getFlyweight("孜然牛肉");
unsharedFlyweight1.getFlyweight("霸王餐");
System.out.println();
String intrinsicState ="木须肉";
Flyweight flyweight1 = unsharedFlyweight1.getFlyweightMap().get(intrinsicState);
Flyweight flyweight2 = unsharedFlyweight2.getFlyweightMap().get(intrinsicState);
System.out.println("不同复合享元对象中的单纯享元对象是否可以共享:" + (flyweight1 == flyweight2));
}
}
享元模式的应用
Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用它。当出现下列情形时可以考虑使用Flyweight模式。
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖对象标识。
享元模式的优缺点
优点:
享元模式的优点:减少对象数量,节省内存空间。
缺点:
- 享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
- 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。