享元模式是通过共享的模式减少构建对象的数量,从而减少资源的占用,每当我们需要一个对象时,工厂会尝试从缓存中获取,如果不存在则会创建对象并加入到缓存中,下次再需要同类对象时就直接从缓存中获取而不需要重新创建。
下面将通过生成不同水果的例子来理解享元模式。
//水果接口
public interface Fruit {
}
//水果实现类
public class FruitImpl implements Fruit{
private String type;
private String color;
public FruitImpl(String type) {
this.type = type;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return color+"的"+type;
}
创建水果工厂来管理所有水果对象:
public class FruitFactory {
//水果对象缓存集合,由水果类型进行标识,同一种水果类型约定为同一类相似对象,从而通过享元模式进行共享
public static final Map<String,Fruit> fruitMap = new HashMap<>();
public static synchronized Fruit getFruit(String type,String color){
FruitImpl fruit = (FruitImpl)fruitMap.get(type);
if (Objects.isNull(fruit)){
fruit = new FruitImpl(type);
fruitMap.put(type,fruit);
}
//实时查看当前工厂中有多少实际的对象
System.out.println("当前工厂拥有对象数量:"+fruitMap.size());
fruit.setColor(color);
return fruit;
}
}
创建测试方法进行测试:
public class Main {
public static void main(String[] args) {
FruitImpl fruit1 = (FruitImpl)FruitFactory.getFruit("苹果", "红色");
System.out.println(fruit1);
FruitImpl fruit2 = (FruitImpl)FruitFactory.getFruit("苹果", "绿色");
System.out.println(fruit2);
FruitImpl fruit3 = (FruitImpl)FruitFactory.getFruit("香蕉", "黄色");
System.out.println(fruit3);
FruitImpl fruit4 = (FruitImpl)FruitFactory.getFruit("香蕉", "绿色");
System.out.println(fruit4);
FruitImpl fruit5 = (FruitImpl)FruitFactory.getFruit("苹果", "青色");
System.out.println(fruit5);
}
}
程序运行结果:
我们从水果工厂中拿到了5种不同的水果,但是实际创建的对象只有两个,这就是共享的思维,所有同类型的水果都是同一个对象。
在java中的常量池也是采用的享元模式。看下面这个例子:
public class Main {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);
Integer i1 = Integer.valueOf(127);
Integer i2 = Integer.valueOf(127);
System.out.println(i1==i2);
Integer i3 = Integer.valueOf(128);
Integer i4 = Integer.valueOf(128);
System.out.println(i3==i4);
}
}
程序运行结果:
s1,s2都是字符串"abc",这种字符串常量都保存在常量池中,不管创建多少个"abc"的字符串对象所以他们都是指向同一个对象,结果固然是true;
i1,i2是同一个对象,i3,i4却不是同一个对象,这是因为Integer常量的范围是-128到127在这个范围内才是从常量池中获取,否则就是新创建的对象。
享元模式优点:
- 极大减少内存中对象的数量,可以节约系统资源,提高系统性能。
享元模式缺点:
- 提升系统复杂度,使用者需要分离出外部状态和内部状态,处理不好容易造成系统的混乱。