享元模式

1,364 阅读4分钟

这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

享元模式

概念

享元模式(Flyweight Pattern)又称为轻量级模式,是对线程池的一种实现。主要用于减少创建对象的数量,来减少内存占用和提高型男,跟线程池蕾类似,线程池可以避免不停的创建和销毁多个对象,消耗性能,根据设计模式分类,享元模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式的主要目的是运用共享技术有效地支持大量细粒度的对象,将多个对于同一对象的访问集中起来

系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。

应用场景

  • 数据库连接池

  • 所有的池化技术

  • 系统需要实现大量的相似对象

  • 需要区分内部状态和外部状态的类

基本用法

一般情况下享元模式分为三种角色

  • 抽象享元角色(IFlyweight): 享元对象抽象基类或者接口,同时定义出对象的外部状态和内部状态的接口实现,主要是提供需要实现的公共接口

  • 享元工厂角色(FlyweightFactory): 主要负责创建和管理享元角色。判断是否存在符合要求的享元对象,如果存在则直接拿取,如果不存在的话就会创建一个享元对象并保存。

  • 具体享元角色(ConcreteFlyweight): 继承于抽象享元角色。实现抽象享元角色定义的义务,该角色的内部状态于环境无关,不会出现有一个操作修改了修改内部环境状态,同时修改了外部状态的情况。

  • IFlyweight:抽象享元角色

public interface IFlyweight {
    void operation(String extrinsicState);
}
  • FlyweightFactory:享元工厂角色
public class FlyweightFactory {
    private static Map<String, IFlyweight> pool = new HashMap<String, IFlyweight>();
    public static IFlyweight getFlyweight(String intrinsicState) {
        if (!pool.containsKey(intrinsicState)) {
            IFlyweight flyweight = new ConcreteFlyweight(intrinsicState);
            pool.put(intrinsicState, flyweight);
        }
        return pool.get(intrinsicState);
    }
}
  • ConcreteFlyweight:具体享元角色
public class ConcreteFlyweight implements IFlyweight {
    private String intrinsicState;
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
    @Override
    public void operation(String extrinsicState) {
        System.out.println("Object address: " + System.identityHashCode(this));
        System.out.println("IntrinsicState: " + this.intrinsicState);
        System.out.println("ExtrinsicState: " + extrinsicState);
    }
}
  • UML结构图

image.png

享元模式的内部状态和外部状态

上述享元模式的概念为我们提供了两个要求,细粒度和共享对象。因为我们知道分配了太多的对象到程序中会很容易会造成内存溢出,如果要避免内存溢出的情况,那么就需要使用到共享技术,但是有因为要求细粒度对象,所以也会不可避免的使对象数量多切性质接近,那么就需要将对象的信息分为两个部分:内部状态和外部状态

我们知道如果细粒度对象,所以不可避免的会导致分配的对象过多,并且这些对象会有很多相似的地方,

  • 内部状态指对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变;

  • 外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。

    我们举一个简单的例子,连接池中的连接对象,保存着用户名、密码、连接的url等信息,在创建对象时就设置好的,不会随着环境的改变而改变,这些都成为内部状态,而每个连接都需要回收利用时,我们需要将这些连接都标记为回收状态,然后设置为可用状态,这样就是外部状态。

享元模式的优缺点

优点

  • 1、享元模式的优点在于它能够极大的减少系统中对象的个数。

  • 2、享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

缺点

  • 1、由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。

  • 2、为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。