文章内容
一、什么是享元模式
享元模式,运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来最大程度减少需要创建的对象数量,避免大量相似对象的开销,从而提高系统资源的利用率。
享元模式,也叫作蝇量模式,属于结构型设计模式。
二、享元模式类图
三、享元模式角色
- 抽象享元角色(FlyWeight): 要求是一个抽象类或接口,声明抽象方法,这些方法需要具体享元类来实现,并向外界提供享元对象的内部状态数据及外部状态数据。
- 具体享元角色(ConcreteFlyWeight): 它继承或实现了抽象享元类,称为享元对象,需要通过享元工厂类来提供唯一的享元对象。
- 非享元角色(UnshareConcreteFlyWeight): 不能被共享的子类可设计为非共享具体享元类,它代表了享元对象的外部状态。非享元对象可以直接作为享元对象方法的参数进行传递。
- 享元工厂角色(FlyWeightFactory): 负责创建和管理享元对象,客户端直接通过享元工厂对象来获取所需要的享元对象。
四、享元模式两种状态
- 内部状态:不会随环境改变而改变的可共享部分。比如围棋的颜色就两种(白棋、黑棋)。
- 外部状态:随环境改变而改变的不可以共享的部分。比如围棋的位置(也就是坐标)。
五、享元模式优缺点
1、优点
- 极大减少内存中共享对象的数量,节约内存资源,提高系统性能。
- 享元模式中外部状态相对独立,且不影响内部状态。
2、缺点
- 需要将享元对象的状态,分离为内部状态和外部状态,程序逻辑变得复杂了。
六、享元模式demo示例
1、Demo需求
以围棋为例,通过享元模式来实现,其中把白棋、黑棋作为具体享元类,白色、黑色是内部状态,围棋的坐标位置是外部状态。
2、数据类定义
/**
* @Description: 非享元角色类(外部状态,棋子坐标)
**/ public class GoChessPoint {
// x 坐标
private double x;
// y 坐标
private double y;
public GoChessPoint(double x, double y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "棋子坐标{" +
"x=" + x +
", y=" + y +
'}';
}
}
3、抽象类定义
/**
* @Description: 抽象享元角色:围棋类
**/ public abstract class AbstractGoChess {
public abstract void show(GoChessPoint point);
}
4、具体化对象类
/**
* @Description: 具体享元角色类:白棋
**/ public class WhiteGoChess extends AbstractGoChess {
@Override
public void show(GoChessPoint point) {
System.out.println("白棋, " + point);
}
}
/**
* @Description: 具体享元角色类:黑棋
**/ public class BlackGoChess extends AbstractGoChess {
@Override
public void show(GoChessPoint point) {
System.out.println("黑棋, " + point);
}
}
5、工厂类定义
/**
* @Description: 享元工厂角色:围棋工厂类
**/ public class GoChessFactory {
// 饿汉式模式实例化单例对象
private static GoChessFactory goc = new GoChessFactory();
// 存放白棋/黑棋对象
private Map<String, AbstractGoChess> goChessMap = new HashMap<>();
// 私有化默认构造方法
private GoChessFactory() {
goChessMap.put("白棋", new WhiteGoChess());
goChessMap.put("黑棋", new BlackGoChess());
}
// 获取单例对象
public static GoChessFactory GetInstance() {
return goc;
}
/**
* 获取棋子对象
*
* @param name
* @return
*/ public AbstractGoChess getGoChess(String name) {
return goChessMap.get(name);
}
}
6、测试
/**
* @Description: 享元模式客户端:围棋客户端测试类
**/ public class GoClient {
public static void main(String[] args) {
// 获取白棋对象
AbstractGoChess white1 = GoChessFactory.GetInstance().getGoChess("白棋");
AbstractGoChess white2 = GoChessFactory.GetInstance().getGoChess("白棋");
// 获取黑棋对象
AbstractGoChess black1 = GoChessFactory.GetInstance().getGoChess("黑棋");
AbstractGoChess black2 = GoChessFactory.GetInstance().getGoChess("黑棋");
// 展示白棋1
white1.show(new GoChessPoint(11.5, 20.8));
// 展示白棋2
white2.show(new GoChessPoint(11.5, 20.8));
System.out.println("white1==white2: " + (white1 == white2));
System.out.println("===============================");
// 展示黑棋1
black1.show(new GoChessPoint(21.5, 26.7));
// 展示黑棋2
black2.show(new GoChessPoint(16.1, 28.3));
System.out.println("black1==black2: " + (black1 == black2));
}
}
白棋, 棋子坐标{x=11.5, y=20.8}
白棋, 棋子坐标{x=11.5, y=20.8}
white1==white2: true
===============================
黑棋, 棋子坐标{x=21.5, y=26.7}
黑棋, 棋子坐标{x=16.1, y=28.3}
black1==black2: true