享元模式(Flyweight Pattern):池技术的重要实现方式,可以降低大量重复的,细粒度的类在内存中的开销
Use sharing to support large numbers of fine-grained objects efficiently.
运用共享技术有效地支持大量细粒度的对象。
掌握享元模式的关键在于区分内部状态和外部状态:
- 内部状态:存储在享元对象内部的,可以共享的信息,不会随环境的改变而改变,可变性小
- 外部状态:随环境改变而改变,不可共享,由客户端输入保存,在需要的时候再传入
享元模式的四种角色:
- 抽象享元(Flyweight)角色:对享元类进行抽象,如果模式中有需要外部状态可以首先以参数的形式定义
- 具体享元(Concrete Flyweight)角色:抽象享元角色的实现,在该类中定义内部状态,由于内部状态不随环境改变,故可定义内部状态为私有
- 享元工厂(Flyweight Factory)角色:构造一个池容器,负责创建和管理享元角色,提供获得享元角色的静态方法,保证已存在的实例对象的唯一,常将工厂的构造方法定义为私有
- 客户端(Clinet)角色:需要自行存储所有享元对象的外部状态
java基础类库中大量使用了享元模式,如String、Integer、Boolean、Character等类都通过享元模式提供了内部的池化机制
列:
String str1="hello java!";
String str2="hello java!";
System.out.println(str1.equals(str2));
//结果为 true
返回值为true,表示这两个字符串是相同的实例;
享元模式基础代码实现:
import java.util.HashMap;
import java.util.Map;
public class FlyweightModel {
/*
* 享元模式
*/
public static void main(String[] args) {
String intrinsicState="in";
Flyweight flyweight=FlyweightFactory.getFlyweight(intrinsicState);
flyweight.operation("ex");
}
}
//抽象享元角色
interface Flyweight{
void operation(String extrinsicState);//参数为外部状态
}
//具体享元角色
class ConcreteFlyweight implements Flyweight{
private String intrinsicState;//内部状态
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState=intrinsicState;
}
@Override
public void operation(String extrinsicState) {
System.out.println("内部状态:"+intrinsicState+"\n"+"外部状态:"+extrinsicState);
}
}
//享元工厂角色
class FlyweightFactory{
private static Map<String, Flyweight> pool=new HashMap<String, Flyweight>();
private FlyweightFactory() {};
public static Flyweight getFlyweight(String intrinsicState) {
Flyweight flyweight=pool.get(intrinsicState);
if(flyweight==null) {
flyweight=new ConcreteFlyweight(intrinsicState);
pool.put(intrinsicState, flyweight);
}
return flyweight;
}
}
运行结果:
内部状态:in
外部状态:ex
享元模式围棋落子实例:
——围棋和五子棋只有黑白两色,所以颜色应该是棋子的内部状态,而棋子之间的不同在于位置不同,所以方位坐标应该是棋子的外部状态,强调棋子对象减少到只有两个实例
public class FlyweightModel {
/*
* 享元模式—围棋落子
*/
public static void main(String[] args) {
String color="黑";
int x=0;
int y=0;
WQFlyweight wqFlyweight;
for(int i=0;i<5;i++) {
x=(int)(19*Math.random());
y=(int)(19*Math.random());
wqFlyweight=WQFlyweightFactory.getWQFlyweight(color);
if(color.equals("黑")) {
color="白";
}else {
color="黑";
}
if(wqFlyweight!=null) {
wqFlyweight.put(x, y);
}
}
}
}
//享元模式实现围棋落子
//1、抽象享元类(外部状态(x,y))
interface WQFlyweight{
void put(int x,int y);//外部状态,棋子位置
}
//2、具体享元类(内部状态(黑,白))
class WQConFlyweight implements WQFlyweight{
private String color;
public WQConFlyweight(String color) {
this.color=color;
}
@Override
public void put(int x, int y) {
System.out.println(color+"子:落于"+"("+x+","+y+")"+"位置");
}
}
//3、享元工厂类
class WQFlyweightFactory{
//确保内部状态实例只有两个
private static WQFlyweight WHITE;
private static WQFlyweight BLACK;
private WQFlyweightFactory() {};
public static WQFlyweight getWQFlyweight(String color) {
if(color.equals("白")) {
if(WHITE==null) {
WHITE=new WQConFlyweight("白");
}
return WHITE;
}else if(color.equals("黑")) {
if(BLACK==null) {
BLACK=new WQConFlyweight("黑");
}
return BLACK;
}
return null;
}
}
运行结果:
黑子:落于(7,12)位置
白子:落于(9,10)位置
黑子:落于(4,10)位置
白子:落于(11,2)位置
黑子:落于(10,14)位置
参考书籍:
《大话设计模式》——程杰
《设计模式(Java版)》