[设计模式] 浅谈享元模式

2024 年 4 月 29 日 星期一
/ ,
4

享元模式

模式功能说明:通过共享的方式高效的支持大量细粒度的对象。

模式思路与原理

在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
主要角色:

  1. Flyweight(抽象享元类):通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。
  2. ConcreteFlyweight(具体享元类):为内部状态提供成员变量进行存储。
  3. UnsharedConcreteFlyweight(非共享具体享元类):通常是将Flyweight子类作为对象的成员,组合成复合对象,复合对象并不是共享的,它们就是非共享具体享元类。
  4. 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对象,这就是享元模式的优点,它可以减少系统中的对象数量。

优缺点

优点:

  1. 可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。

  2. 可以通过设置外部状态使得复用对象。

缺点:

  1. 使系统更加复杂,需要分离出内部状态和外部状态,而外部状态具有固化特性,一旦一个新的外部状态需要共享,就需要修改源代码,违背了开闭原则。

总结

享元模式使用了设计模式中的单一职责原则和复用原则。 通过共享技术实现相同或相似对象的重用。在对象数量巨大时,可以极大地减少系统的对象数量,节省内存。但是,它使系统变得复杂,需要分离出内部状态和外部状态,而且外部状态具有固化特性,一旦一个新的外部状态需要共享,就需要修改源代码,违背了开闭原则。

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...