在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈。例如,围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源,这就是享元模式的产生背景。
享元模式中存在以下两种状态:
内部状态,即不会随着环境的改变而改变的可共享部分; 外部状态,指随环境改变而改变的不可以共享的部分。享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。下面来分析其基本结构和实现方法。
模式的结构:
享元模式的主要角色有如下。
抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
以五子棋为例: 棋子就是抽象享元角色,黑棋子和白棋子就是具体的享元角色,棋子的坐标就是非享元角色。
package flyweight; import java.util.HashMap; public class Main { public static void main(String[] args) { Chess white = ChessFactory.getChess("white"); Chess white2= ChessFactory.getChess("white"); Chess black= ChessFactory.getChess("black"); Chess black2= ChessFactory.getChess("black"); System.out.println(white.hashCode()); System.out.println(white2.hashCode()); System.out.println(black.hashCode()); System.out.println(black2.hashCode()); white.drop(new Point(1,1)); black.drop(new Point(2,2)); white2.drop(new Point(1,2)); } } class Point{ private int x; private int y; public Point(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; } @Override public String toString() { return "(" + "x=" + x + ", y=" + y + ')'; } } interface Chess{ public void drop(Point point); } class BlackChess implements Chess{ @Override public void drop(Point point) { System.out.println("black is at "+point); } } class WhiteChess implements Chess{ @Override public void drop(Point point) { System.out.println("white is at "+point); } } class ChessFactory{ private static HashMap<String,Chess> cache=new HashMap<String,Chess>(); public static Chess getChess(String color){ Chess chess =null; if("white".equals(color)){ chess = cache.get(color); if(chess==null){ chess=new WhiteChess(); cache.put(color,chess); } } if("black".equals(color)){ chess = cache.get(color); if(chess==null){ chess=new BlackChess(); cache.put(color,chess); } } return chess; } }