享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
说简单些就是对现有对象的重用,但这个对象中要区别两部分,一部分称之为内部状态,一部分为外部状态。所谓内部状态就是不会随环境变化的即固定的不变的,可共享的。所谓外部状态就是会变化的,不能共享的。
举个简单的例子。比如设计一个围棋软件,一个棋子就是一个对象,要是每个棋子都做为一个单独的对象的话,那下一盘下来就得创建几百个对象之多(就棋子而言,不计算其他依赖对象)。虽然说这么几百个对服务器来说不是什么问题,得做软件追求的应该是以最少的资源可以得到最大的效益,也就是精益求精嘛,做好点总没有错。为了节约这些个对象的内存资源就要享元模式上场了。
首先,棋子都一样嘛除了颜色,所以棋子就是享元对象。而棋子只有黑白两色,这不就是上面说的内部状态嘛,就黑白两种,总不能下着下着变出红色棋子来吧。而下棋时每个黑棋或白棋的落点位置都是不确定的,所以这也就是上面说的外部状态。理清楚了这些就可以用代码实现下了。
先定义一个抽象享元类AbstractChess,其中定义了内部状态color属性,而外部状态ChessLocation因为是时刻会变化的所以由调用时传入。
package com.minant.flyweight;
/**
* @ClassName AbstractChess
* @Description TODO 抽象棋子类
* @Author MinAnt
* @Date 2020/5/26
* @Version V1.0
*/
public abstract class AbstractChess {
private String color;
public abstract void show(ChessLocation location);
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
package com.minant.flyweight;
/**
* @ClassName ChessLocation
* @Description TODO 棋子的位置
* @Author MinAnt
* @Date 2020/5/26
* @Version V1.0
*/
public class ChessLocation {
int x;
int y;
public ChessLocation(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
具体的享元类就是做了一个简单的描述功能:
package com.minant.flyweight;
/**
* @ClassName RealChess
* @Description TODO 具体享元棋子类
* @Author MinAnt
* @Date 2020/5/26
* @Version V1.0
*/
public class RealChess extends AbstractChess {
@Override
public void show(ChessLocation location) {
System.out.println(getColor() + "棋子的位置在:【"+location.getX()+","+location.getY()+"】");
}
}
最后还有一个核心的享元工厂类,其中用一个HashMap来维护享元对象,一个对外获取享元对象的方法,通过棋子颜色为键,返回相应的棋子对象,map所维护的也就是黑棋和白棋两个对象:
package com.minant.flyweight;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName ChessFactory
* @Description TODO 享元工厂类
* @Author MinAnt
* @Date 2020/5/26
* @Version V1.0
*/
public class ChessFactory {
private static final String CHESS_COLORS[] = {"black", "white"};
protected static Map<String, RealChess> chessMap = new HashMap<>();
public static RealChess getChess(String color) {
int index = Arrays.binarySearch(CHESS_COLORS,color);
if(index<0) {
return null;
}
RealChess exitChess = chessMap.get(color);
if(null == exitChess) {
RealChess realChess = new RealChess();
realChess.setColor(color);
chessMap.put(color, realChess);
exitChess = realChess;
}
return exitChess;
}
}
测试:
package com.minant.flyweight;
/**
* @ClassName TestFlyWeight
* @Description TODO 测试享元模式
* @Author MinAnt
* @Date 2020/5/26
* @Version V1.0
*/
public class TestFlyWeight {
public static void main(String[] args) {
RealChess chessa = ChessFactory.getChess("black");
RealChess chessb = ChessFactory.getChess("white");
RealChess chessc = ChessFactory.getChess("black");
RealChess chessd= ChessFactory.getChess("white");
System.out.println(chessa);
System.out.println(chessb);
System.out.println(chessc);
System.out.println(chessd);
System.out.println("************修改外部不共享状态***********");
chessa.show(new ChessLocation(1,2));
chessb.show(new ChessLocation(1,3));
chessa.show(new ChessLocation(1,5));
chessb.show(new ChessLocation(3,2));
}
}
运行结果:
可以从结果看出,黑棋始终是一个对象,白棋也始终是一个对象,变化的是棋子的位置状态,这就是享元模式。