4)完整解决方案-不带外部状态
1.结构图
IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。
2.代码案例
抽象享元类
//围棋棋子类:抽象享元类
abstract class IgoChessman {
public abstract String getColor();
public void display() {
System.out.println("棋子颜色:" + this.getColor());
}
}
具体享元类
//黑色棋子类:具体享元类
public class BlackIgoChessman extends IgoChessman {
public String getColor() {
return "黑色";
}
}
//白色棋子类:具体享元类
public class WhiteIgoChessman extends IgoChessman {
public String getColor() {
return "白色";
}
}
享元工厂类
import java.util.Hashtable;
//围棋棋子工厂类:享元工厂类,使用单例模式进行设计
public class IgoChessmanFactory {
private static IgoChessmanFactory instance = new IgoChessmanFactory();
private static Hashtable ht; //使用Hashtable来存储享元对象,充当享元池
private IgoChessmanFactory() {
ht = new Hashtable();
IgoChessman black, white;
black = new BlackIgoChessman();
ht.put("b", black);
white = new WhiteIgoChessman();
ht.put("w", white);
}
//返回享元工厂类的唯一实例
public static IgoChessmanFactory getInstance() {
return instance;
}
//通过key来获取存储在Hashtable中的享元对象
public static IgoChessman getIgoChessman(String color) {
return (IgoChessman) ht.get(color);
}
}
客户端类
public class Client {
public static void main(String[] args) {
IgoChessman black1, black2, black3, white1, white2;
IgoChessmanFactory factory;
//获取享元工厂对象
factory = IgoChessmanFactory.getInstance();
//通过享元工厂获取三颗黑子
black1 = factory.getIgoChessman("b");
black2 = factory.getIgoChessman("b");
black3 = factory.getIgoChessman("b");
System.out.println("判断两颗黑子是否相同:" + (black1 == black2));
//通过享元工厂获取两颗白子
white1 = factory.getIgoChessman("w");
white2 = factory.getIgoChessman("w");
System.out.println("判断两颗白子是否相同:" + (white1 == white2));
//显示棋子
black1.display();
black2.display();
black3.display();
white1.display();
white2.display();
}
}
5)完整解决方案-带外部状态
1.结构图
增加了一个坐标类Coordinates,同时抽象享元类IgoChessman中的display()方法也对应增加一个Coordinates类型的参数,用于在显示棋子时指定其坐标。
2.代码案例
//坐标类:外部状态类
@AllArgsConstructor
@Data
public class Coordinates {
private int x;
private int y;
}
//围棋棋子类:抽象享元类
abstract class IgoChessman {
public abstract String getColor();
public void display(Coordinates coord){
System.out.println("棋子颜色:" + this.getColor() + ",棋子位置:" + coord.getX() + "," + coord.getY() );
}
}
//客户端类
public class Client {
public static void main(String[] args) {
IgoChessman black1,black2,black3,white1,white2;
IgoChessmanFactory factory;
//获取享元工厂对象
factory = IgoChessmanFactory.getInstance();
//通过享元工厂获取三颗黑子
black1 = factory.getIgoChessman("b");
black2 = factory.getIgoChessman("b");
black3 = factory.getIgoChessman("b");
System.out.println("判断两颗黑子是否相同:" + (black1==black2));
//通过享元工厂获取两颗白子
white1 = factory.getIgoChessman("w");
white2 = factory.getIgoChessman("w");
System.out.println("判断两颗白子是否相同:" + (white1==white2));
//显示棋子,同时设置棋子的坐标位置
black1.display(new Coordinates(1,2));
black2.display(new Coordinates(3,4));
black3.display(new Coordinates(1,3));
white1.display(new Coordinates(2,5));
white2.display(new Coordinates(2,4));
}
}
6)单纯享元模式和复合享元模式
1.单纯享元模式
在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。
2.复合享元模式
将一些单纯享元对象使用组合模式加以组合,可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。
如果希望为多个内部状态不同的享元对象设置相同的外部状态,可以考虑使用复合享元模式。
3.享元模式和其他模式联用
-
在享元模式的享元工厂类中通常提供一个静态的工厂方法用于返回享元对象,使用简单工厂模式来生成享元对象。
-
在一个系统中,通常只有一个享元工厂,可以使用单例模式进行享元工厂类的设计。
-
享元模式可以结合组合模式形成复合享元模式,统一对多个享元对象设置外部状态。
7)总结
1.优点
-
可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,可以节约系统资源,提高系统性能。
-
享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
2.缺点
-
享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
-
为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
3.适用场景
-
一个系统有大量相同或者相似的对象,造成内存的大量耗费。
-
对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
-
使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,应当在需要多次重复使用享元对象时才值得使用享元模式。