享元模式
0.前言
我们经常使用word来编辑文档,但是在word中,很多汉字我们已经输入过,但是word内部还会让这些汉字占用内存么?事实上,【word并没有让这些重复的汉字重复占用内存,】这些相同的汉字使用的是相同的内存地址。接下来,我们来看一个简单的程序。
public class Test {
public static void main(String [] args){
String str1 = "abcd";
String str2 = "abcd";
System.out.println(str1 == str2);
String str3 = "ab"+"cd";
System.out.println(str2 == str3);
String str4 = "ab";
str4 +="cd";
System.out.println(str2 == str4);
}
}
实现结果

1.简介
运用 共享技术支持 大量细粒度对象的复用,系统只使用少量的对象,而这些对象的都很相似,状态的变化很小,可以实现对象的多次 复用,由于享元模式要求能够共享的对象必须是细粒度对象,因此又称为 轻量级模式。2.实际案例
在围棋中,所有的黑色棋子是一样的,所有的白色棋子是一样的。请用享元模式实现。3.具体分析
围棋中有两种棋子,分别是BlackChessPiece,WhiteChessPiece,这两个类都继承自Flyweight。对于要生产大量的细粒度对象,我们可以使用工厂方法(工厂类),于是有了FlyweightFactory,用以生产享元对象。综上所述得以下几类:- FlyweightFactory:享元工厂类【Flyweight享元模式】
- ChessPiece:抽象棋子类(抽象享元类)
- BlackChessPiece:黑色棋子类,【继承自Flyweight】
- WhiteChessPiece:白色棋子类,【继承自Flyweight】
- Client:客户端类
4.具体实现
package liu.shen;
/**
* 客户端类
* @author Object
*
*/
public class Client {
public static void main(String [] args){
ChessPiece blackChessPiece1,blackChessPiece2,whiteChessPiece1,whiteChessPiece2;//四枚棋子
FlyweightFactory factory ;
factory = FlyweightFactory.getFactoryInstance();//返回工厂实例
//通过享元工厂获取四颗棋子
blackChessPiece1 = factory.getChessPieceInstance("b");
blackChessPiece2 = factory.getChessPieceInstance("b");
whiteChessPiece1 = factory.getChessPieceInstance("w");
whiteChessPiece2 = factory.getChessPieceInstance("w");
System.out.print("blackChessPiece1 与 blackChessPiece2相同吗?");
System.out.println(blackChessPiece1 == blackChessPiece2);
System.out.print("whiteChessPiece1 与 whiteChessPiece2相同吗?");
System.out.println(whiteChessPiece1 == whiteChessPiece2);
System.out.println(blackChessPiece1 == null);
//这里我们可以看到blackChessPiece1以及其他的都不为Null对象
blackChessPiece1.display();
blackChessPiece2.display();
whiteChessPiece1.display();
whiteChessPiece2.display();
}
}
package liu.shen;
/**
* 黑色棋子类
* @author Object
*
*/
public class BlackChessPiece extends ChessPiece{
@Override void display() {
System.out.print("我是一枚黑色的棋子! "); //
coordinate.show(); }
}
package liu.shen;
/**
* 棋子类,相当于抽象享元类
* @author Object
**/
public abstract class ChessPiece {
abstract void display();
public void show(Coordinate coordinate){
coordinate.show();
}
}
package liu.shen;
/**
* 白色棋子类
* @author Object
* */
public class WhiteChessPiece extends ChessPiece{
@Override void display() {
System.out.print("我是一枚白色的棋子! ");
coordinate.show();
}
}
package liu.shen;
import java.util.Hashtable;
/**
* 享元工厂类,用以生产大量的细粒度对象
* @author Object
* */
public class FlyweightFactory {
private static FlyweightFactory flyweightFactory = new FlyweightFactory();
private static Hashtable ht;//使用Hashtable类存储享元对象,充当享元池
private FlyweightFactory(){
ht = new Hashtable();
ChessPiece black,white;
black = new BlackChessPiece();
white = new WhiteChessPiece();
ht.put("b", black);
ht.put("w", white);
}
public static FlyweightFactory getFactoryInstance(){
return flyweightFactory;
} //根据颜色,返回棋子
public static ChessPiece getChessPieceInstance(String color){
return (ChessPiece)ht.get(color);
}
5实现结果
6.总结
这里我们使用工厂模式生产两个对象。但是假设在一个围棋中,有很多棋子,棋子的位置各不相同,我们该怎么实现呢?
针对上述情况,我们可以使用一个叫做Coordinate的类专门用作管理棋子的位置。为了能够实现针对抽象编程的目的,我们可以在抽象类Flyweight类的中的方法使用Coordinate类的对象【依赖关系】来实现此功能。所以添加的类有:
Coordinate:位置类,用以表示棋子的位置
blackChessPiece1.display();
blackChessPiece1.show(new Coordinate(1,2));
blackChessPiece2.display();
blackChessPiece2.show(new Coordinate(3,4));
whiteChessPiece1.display();
whiteChessPiece1.show(new Coordinate(5,6));
whiteChessPiece2.display();
whiteChessPiece2.show(new Coordinate(7,8));
package liu.shen;
/**
* 用以表示棋子的位置类
* @author Object
*
*/
public class Coordinate {
private int xLabel,yLabel;//表示x轴,y轴
public Coordinate(int xLabel,int yLabel){
this.xLabel = xLabel;
this.yLabel = yLabel;
}
/*xLabel与yLabel对象的get和set方法*/
public int getxLabel() {
return xLabel;
}
public void setxLabel(int xLabel) {
this.xLabel = xLabel;
}
public int getyLabel() {
return yLabel;
}
public void setyLabel(int yLabel) {
this.yLabel = yLabel;
}
public void show(){
System.out.println("行:"+this.getyLabel()+"列:"+this.getxLabel());
}
}
7.模式总结
(1)我们可以看到这里的实现只是在享元工厂中关联了抽象享元类,然后使用Hashtable类将几个抽象享元对象放到表中,在我们需要时(Client类),再调用FlyweightFactory类中getChessPiece()方法,从而获取实例对象。
(2)在现实生活中,我们经常遇到的情况是,一些对象肯定还会有一个附加属性,而这些附加属性该怎么体现呢?这里的实现是:将附加属性Attribute作为一个类单独存在,然后在ChessPiece类中使用一个方法,在其中使用Attribute的对象作为参数,然后调用即可。
(3)我始终觉得这个模式实现起来很别扭,不就是类似于一个原型模式嘛,但是这里的clone()方法变成了getChessPiece()方法,所以每次生产出来的对象都是一样的。因为我都是从一个Hashtable表中得出来的,然后得到的对象就全部是一个样子(连内存地址都是一样)。
(4)所以说享元模式很简单,总结起来就这么一句话:有一个享元工厂专门负责生产本质上一样,表现层却不同的享元对象。
















