享元模式(Flyweight Pattern),主要作用就是用来共享,共享重复元素,从而达到节省内存的目标。
如果一个类被大量创建使用,并且这个对象本身的属性在使用方那里又不会被改变,那么这个对象就可以被共享,被任意多的类或对象拿去共享。
举例来说,如果让你实现一个五子棋游戏,当一方落一子,这时你是不是new一个黑子或白子,并记录位置呢,那一个棋盘棋子的颜色只有黑白两种,只是位置不同,这时候每个棋子都new一份,一盘棋下来,棋盘的棋子的颜色属性是重复的,就会造成内存的浪费。
这仅仅是一盘棋,如果你要实现一个五子棋游戏大厅,同一时间在线人数达到百万,棋子数可能达到千万甚至几亿数十亿颗,那么这个内存就非常可观了,优化内存也就是必须要做的了。
1、定义共享部分,这里也就是棋子的颜色部分是共享的,所以抽出来作为一个单独的类
package com.itzhimei.study.design.flyweight;
/**
* @Auther: www.itzhimei.com
* @Description: 棋子的享元部分
*/
public class ChessPieceFlyweight {
private ChessPieceColorEnum color;
public ChessPieceFlyweight(ChessPieceColorEnum color) {
this.color = color;
}
public ChessPieceColorEnum getColor() {
return color;
}
}
这里只有get颜色方法,没有set颜色方法,因为颜色是固定的,不应该被修改。
2、定义了棋子颜色枚举类,这里在代码中直接写“白”和“黑”也是可以的
package com.itzhimei.study.design.flyweight;
/**
* @Auther: www.itzhimei.com
* @Description: 棋子颜色
*/
public enum ChessPieceColorEnum {
RED,BLACK
}
3、定义共享部分的生产工厂,防止重复创建
package com.itzhimei.study.design.flyweight;
import java.util.HashMap;
import java.util.Map;
/**
* @Auther: www.itzhimei.com
* @Description: 棋子享元工厂类
*/
public class ChessPieceFWFactory {
private static final Map<Integer, ChessPieceFlyweight> ps = new HashMap();
static {
ps.put(1,new ChessPieceFlyweight(ChessPieceColorEnum.RED));
ps.put(2,new ChessPieceFlyweight(ChessPieceColorEnum.BLACK));
}
public static ChessPieceFlyweight getChessPieceFlyweight(int type) {
return ps.get(type);
}
}
我们在类中使用静态代码块来实现白子和黑子,只创建一份,并放入map中。
4、棋子类
package com.itzhimei.study.design.flyweight;
/**
* @Auther: www.itzhimei.com
* @Description: 其子类
*/
public class ChessPiece {
//棋子共享部分--颜色
private ChessPieceFlyweight chessPieceFlyweight;
//棋子坐标
private int positionX;
private int positionY;
public ChessPiece(ChessPieceFlyweight fw, int positionX, int positionY) {
this.chessPieceFlyweight = fw;
this.positionX = positionX;
this.positionY = positionY;
}
@Override
public String toString() {
String s = "positionX:" + this.positionX + "---this.positionY:" + this.positionY + "---棋子颜色:" + this.chessPieceFlyweight.getColor();
return s;
}
}
棋子类中有棋子的X和Y坐标,并且有共享部分:棋子颜色。
棋子的颜色统一从工厂中获取的,全局只有一份,所以实现了节省内存。
5、测试
package com.itzhimei.study.design.flyweight;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class Client {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
if(i%2 == 0) {
ChessPiece chessPiece = new ChessPiece(ChessPieceFWFactory.getChessPieceFlyweight(1), i + 1, i + 1);
System.out.println(chessPiece);
} else {
ChessPiece chessPiece = new ChessPiece(ChessPieceFWFactory.getChessPieceFlyweight(2), i + 1, i + 1);
System.out.println(chessPiece);
}
}
}
}
输出:
positionX:1---this.positionY:1---棋子颜色:RED
positionX:2---this.positionY:2---棋子颜色:BLACK
positionX:3---this.positionY:3---棋子颜色:RED
positionX:4---this.positionY:4---棋子颜色:BLACK
positionX:5---this.positionY:5---棋子颜色:RED
positionX:6---this.positionY:6---棋子颜色:BLACK
positionX:7---this.positionY:7---棋子颜色:RED
positionX:8---this.positionY:8---棋子颜色:BLACK
positionX:9---this.positionY:9---棋子颜色:RED
positionX:10---this.positionY:10---棋子颜色:BLACK
类关系图:
享元模式的目标就是节省内存,如果有大量重复对象创建,并且需要节省内存,那么你就要考虑使用享元模式了。