Java设计模式 – 享元模式
概念
如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。在享元模式中,由于需要构造和维护这些可以共享的对象,因此,常会出现一个工厂类,用于维护和创建对象。
结构
- 享元工厂:用于创建具体享元类,维护相同的享元对象。它保证相同的享元对象可以被系统共享。即,其内部使用了类似单例模式的方法,当请求对象已经存在时,直接返回对象,不存在时,在创建对象。
- 抽象享元:定义需要共享的对象业务接口。享元类被创建出来总是为了实现某些特定的业务逻辑,而抽象享元便定义这些逻辑的语义行为。
- 具体享元类:实现抽象享元类的接口,完成某一具体逻辑。
- 客户端:使用享元模式的组件,通过享元工厂取得享元对象。
案例
我们学习了建造者模式时,用的英雄的案例,那么我们继续以这个为例子。假设每一个英雄都是有类型的,比如法师、坦克、刺客等。这种类型我们可以顶一个类,但是如果每新建立一个英雄就要去新建一个“类型”类就会非常占用内存,此时我们就可以使用享元模式来解决。
创建Flyweight接口
public interface Flyweight {
void operation(String hero);
}
创建ConcreteFlyweight(享元对象),实现接口
public class ConcreteFlyweight implements Flyweight{
private String type;
public ConcreteFlyweight(String type) {
this.type = type;
}
@Override
public void operation(String hero) {
System.out.println("英雄是: " + hero + ", 类型: " + type);
}
}
创建FlyweightFactory,用来维护享元池
public class FlyweightFactory {
private static Map<String, Flyweight> map = new HashMap<>();
public static Flyweight getFlyweight(String type) {
if (map.containsKey(type)) {
return map.get(type);
}else {
ConcreteFlyweight concreteFlyweight = new ConcreteFlyweight(type);
map.put(type, concreteFlyweight);
return concreteFlyweight;
}
}
public static void getTotal() {
System.out.println("总共创建了" + map.size() + "个对象");
}
}
客户端测试
public class Client {
public static void main(String[] args) {
Flyweight f1 = FlyweightFactory.getFlyweight("坦克");
Flyweight f2 = FlyweightFactory.getFlyweight("法师");
Flyweight f3 = FlyweightFactory.getFlyweight("刺客");
f1.operation("屠夫");
f2.operation("冰女");
f3.operation("影刺");
f3.operation("幻刺");
FlyweightFactory.getTotal();
}
}
英雄是: 屠夫, 类型: 坦克
英雄是: 冰女, 类型: 法师
英雄是: 影刺, 类型: 刺客
英雄是: 幻刺, 类型: 刺客
总共创建了3个对象
优点
享元模式是一个非常简单的模式,它可以大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能,但它同时也提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统的逻辑混乱。
场景
- 系统中存在大量的相似对象。
- 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份。
- 需要缓冲池的场景。