享元模式
Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意。享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。
顾名思义:共享元对象。如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用创建新的对象。享元模式是为数不多的、只为提升系统性能而生的设计模式。它的主要作用就是复用大对象(重量级对象),以节省内存空间和对象创建时间。
角色
1、Flyweight:享元接口,通过这个接口Flyweight可以接受并作用于外部状态。通过这个接口可以传入外部的状态,在享元对象的方法处理中可能会使用这些外部的数据。 2、ConcreteFlyweight:具体的享元实现对象,必须是共享的,需要封装Flyweight的内部状态。 3、UnshareConcreteFlyweight:非共享的享元实现对象,并不是所有的Flyweight实现对象都需要共享。非共 享的享元实现对象通常是对享元对象的组合对象。 4、FlyweightFactoty:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。 5、Client: 享元客户端,主要的工作就是维持一个对Flyweight的引用,计算或存储享元的外部状态,当然这里可访问共享和不共享的Flyweight对象。
一、代码实现 1.1、享元接口/**
享元接口:通过这个接口,接受并作用于外部状态
通过这个接口可以传入外部状态,在享元的对象方法处理中可能用到这些外部数据
*/
public interface ChessFlyWeight {
/**
* 设置棋子的颜色
* @param color
*/
void setColor(String color);
/**
* 获取棋子的颜色
* @return
*/
String getColor();
void display(Coordinate coordinate);
}
1.2、具体享元对象
/**
具体享元对象: 具体的享元实现对象,必须是共享的,需要封装FlayWeight的内部状态
*/
public class ConcreateChess implements ChessFlyWeight{
private String color;
public ConcreateChess(String color) {
super();
this.color = color;
}
@Override
public void setColor(String color) {
this.color = color;
}
@Override
public String getColor() {
return this.color;
}
@Override
public void display(Coordinate coordinate) {
System.out.println("棋子的颜色:"+this.color);
System.out.println("棋子的位置:"+coordinate.getX()+"----"+coordinate.getY());
}
}
辅助类
public class Coordinate {
private int x, y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
1.3、享元工厂
import java.util.HashMap;
import java.util.Map;
/**
享元工厂:主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口
*/
public class ChessFlyWeightFactory {
//享元池
private static Map map= new HashMap();
public ChessFlyWeight getChess(String color) {
if (map.get(color) == null) {
ChessFlyWeight chessFlyWeight = new ConcreateChess(color);
map.put(color, chessFlyWeight);
return chessFlyWeight;
}else {
return map.get(color);
}
}
}
1.4、测试
public class Test {
public static void main(String[] args) {
ChessFlyWeightFactory chessFlyWeightFactory = new ChessFlyWeightFactory();
ChessFlyWeight cfw1 = chessFlyWeightFactory.getChess("红色");
ChessFlyWeight cfw2 = chessFlyWeightFactory.getChess("红色");
System.out.println(cfw1);
System.out.println(cfw2);
System.out.println("增加外部状态的处理===========");
cfw1.display(new Coordinate(10, 10));
cfw2.display(new Coordinate(20, 20));
}
}
输出:
com.chb.k.FlyWeightDesignPattern.ConcreateChess@15db9742
com.chb.k.FlyWeightDesignPattern.ConcreateChess@15db9742
//cfw1和cfw2是同一个对象
增加外部状态的处理===========
棋子的颜色:红色
棋子的位置:10----10
棋子的颜色:红色
棋子的位置:20----20
模式的优缺点
模式的优点
减少对象数量,节省内存空间。
模式的缺点
维护共享对象,需要额外开销。(比如:一个线程来回收垃圾)
思考
模式本质:分离和共享
开发中的应用场景:
享元模式由于其共享的特征,可以在任何“池”中操作,比如:线程池,数据库连接池。
String类的设计也是享元模式。 在JAVA语言中,String类型就是使用了享元模式。String对象是final类型,对象一旦创建就不可改变。在JAVA中字符串常量都是存在常量池中的,JAVA会确保一个字符串常量在常量池中只有一个拷贝。String a=”abc”,其中”abc”就是一个字符串常量。public class Test {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println(a==b);
}
}
//输出结果:
true
这就说明a和b两个引用都指向了常量池中的同一个字符串常量”abc”。这样的设计避免了在创建N多相同对象时所产生的不必要的大量的资源消耗。