[设计模式] 浅谈享元模式
享元模式
模式功能说明:通过共享的方式高效的支持大量细粒度的对象。
模式思路与原理
在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
主要角色:
- Flyweight(抽象享元类):通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。
- ConcreteFlyweight(具体享元类):为内部状态提供成员变量进行存储。
- UnsharedConcreteFlyweight(非共享具体享元类):通常是将Flyweight子类作为对象的成员,组合成复合对象,复合对象并不是共享的,它们就是非共享具体享元类。
- FlyweightFactory(享元工厂类):创建并管理享元对象,享元池一般设计成键值对。
案例
//定义了一个Flyweight接口,它有一个operation方法,这个方法接受一个UnsharedConcreteFlyweight对象作为参数。
interface Flyweight {
void operation(UnsharedConcreteFlyweight state);
}
//定义了一个ConcreteFlyweight类,它实现了Flyweight接口,这个类有一个key成员变量,用于区分不同的ConcreteFlyweight对象。
//在operation方法中,它会打印出自己的key和传入的UnsharedConcreteFlyweight对象的信息。
class ConcreteFlyweight implements Flyweight {
private String key;
ConcreteFlyweight(String key) {
this.key = key;
System.out.println("具体享元" + key + "被创建!");
}
public void operation(UnsharedConcreteFlyweight outState) {
System.out.print("具体享元" + key + "被调用,");
System.out.println("非享元信息是:" + outState.getInfo());
}
}
//定义了一个FlyweightFactory类,它有一个HashMap成员变量,用于存储已经创建的ConcreteFlyweight对象。
//在getFlyweight方法中,它首先检查传入的key是否已经存在于HashMap中,如果存在,就直接返回对应的ConcreteFlyweight对象,否则,就新建一个ConcreteFlyweight对象,存入HashMap,并返回。
class FlyweightFactory {
private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
public Flyweight getFlyweight(String key) {
Flyweight flyweight = flyweights.get(key);
if (flyweight != null) {
System.out.println("具体享元" + key + "已经存在,被成功获取!");
} else {
flyweight = new ConcreteFlyweight(key);
flyweights.put(key, flyweight);
}
return flyweight;
}
}
//UnsharedConcreteFlyweight类是一个简单的类,只有一个info成员变量和对应的getter和setter方法。
class UnsharedConcreteFlyweight {
private String info;
UnsharedConcreteFlyweight(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
public class FlyweightPattern {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight f1 = factory.getFlyweight("a");
Flyweight f2 = factory.getFlyweight("a");
Flyweight f3 = factory.getFlyweight("a");
Flyweight f4 = factory.getFlyweight("b");
Flyweight f5 = factory.getFlyweight("b");
f1.operation(new UnsharedConcreteFlyweight("第1次调用a。"));
f2.operation(new UnsharedConcreteFlyweight("第2次调用a。"));
f3.operation(new UnsharedConcreteFlyweight("第3次调用a。"));
f4.operation(new UnsharedConcreteFlyweight("第1次调用b。"));
f5.operation(new UnsharedConcreteFlyweight("第2次调用b。"));
}
}
我们首先创建了一个FlyweightFactory对象,然后通过这个工厂对象获取了多个Flyweight对象,并调用了它们的operation方法。你可以看到,尽管我们调用了5次getFlyweight方法,但实际上只创建了两个ConcreteFlyweight对象,这就是享元模式的优点,它可以减少系统中的对象数量。
优缺点
优点:
可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
可以通过设置外部状态使得复用对象。
缺点:
- 使系统更加复杂,需要分离出内部状态和外部状态,而外部状态具有固化特性,一旦一个新的外部状态需要共享,就需要修改源代码,违背了开闭原则。
总结
享元模式使用了设计模式中的单一职责原则和复用原则。 通过共享技术实现相同或相似对象的重用。在对象数量巨大时,可以极大地减少系统的对象数量,节省内存。但是,它使系统变得复杂,需要分离出内部状态和外部状态,而且外部状态具有固化特性,一旦一个新的外部状态需要共享,就需要修改源代码,违背了开闭原则。