Spring + 设计模式 (六) 结构型 - 享元模式

51 阅读5分钟

享元模式

引言

享元模式(Flyweight Pattern)是一种创建型设计模式,旨在通过共享对象来减少内存占用和提高性能。其核心思想是将对象的状态分为内部状态(共享、不变)和外部状态(非共享、可变),通过复用内部状态相同的对象,显著降低资源消耗。享元模式如同内存的“精算师”,在对象数量庞大时展现高效优雅,特别适合需要重复创建相似对象的场景。

实际开发中的用途

在实际开发中,享元模式常用于优化内存密集型应用,如文本编辑器中的字符渲染、游戏中的重复对象(如树木、粒子效果)或缓存池管理。它解决了创建大量相似对象带来的内存开销问题,通过共享不变的内部状态,减少对象实例数量,提升系统性能。同时,享元模式通过外部状态隔离变化,确保灵活性,特别适合高并发或资源受限的环境。

开发中的示例

设想一个在线文档编辑系统,每个字符对象包含字体、颜色等属性。如果为每个字符创建独立对象,内存占用将激增。使用享元模式,可以将字体和颜色作为共享的内部状态存储在享元对象中,字符位置作为外部状态由客户端管理。这样,相同字体和颜色的字符共享一个享元对象,大幅降低内存使用,同时保持渲染灵活性。

Spring 源码中的应用

在 Spring 框架中,享元模式在 BeanDefinition 的管理中有所体现。Spring 的 BeanDefinitionRegistryDefaultListableBeanFactory 通过共享 BeanDefinition 对象,优化内存使用。BeanDefinition 存储 Bean 的元数据(如类名、作用域等),这些元数据作为内部状态在容器中共享,而 Bean 的实例状态(如属性值)作为外部状态在运行时动态管理。

以下是 Spring 源码片段(DefaultListableBeanFactory.java):

// Spring 框架中的 DefaultListableBeanFactory
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        // 存储共享的 BeanDefinition 对象
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
        // 获取共享的 BeanDefinition 对象
        BeanDefinition bd = this.beanDefinitionMap.get(beanName);
        if (bd == null) {
            throw new NoSuchBeanDefinitionException(beanName);
        }
        return bd;
    }
}

在这段代码中,beanDefinitionMap 充当享元池,存储共享的 BeanDefinition 对象。每个 BeanDefinition 包含 Bean 的元数据(如类名、依赖关系),这些元数据作为内部状态在容器中共享,供多个 Bean 实例复用。Bean 的运行时状态(如具体属性值)作为外部状态,由 BeanFactory 在实例化时动态注入。享元模式在这里减少了元数据对象的重复创建,优化了 Spring IoC 容器的内存占用,同时通过外部状态隔离了 Bean 实例的差异性,增强了系统的可扩展性。

SpringBoot 代码案例

以下是一个基于 Spring Boot 的享元模式案例,模拟一个图形编辑器,支持大量重复的圆形对象。圆形的颜色作为共享的内部状态,位置作为外部状态,通过享元模式减少内存占用。

// 圆形接口
public interface Circle {
    void draw(int x, int y);
}

// 享元对象 - 圆形
public class CircleFlyweight implements Circle {
    private final String color; // 内部状态,共享

    public CircleFlyweight(String color) {
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("绘制圆形 [颜色: " + color + ", 位置: (" + x + ", " + y + ")]");
    }
}

// 享元工厂
public class CircleFactory {
    private static final Map<String, Circle> circleMap = new HashMap<>();

    public static Circle getCircle(String color) {
        Circle circle = circleMap.get(color);
        if (circle == null) {
            circle = new CircleFlyweight(color);
            circleMap.put(color, circle);
            System.out.println("创建新圆形享元: " + color);
        }
        return circle;
    }
}

// Spring Boot 配置类
@Configuration
public class CircleConfig {
    @Bean
    public CircleFactory circleFactory() {
        return new CircleFactory();
    }
}

// Spring Boot 主程序
@SpringBootApplication
public class Application implements CommandLineRunner {
    @Autowired
    private CircleFactory circleFactory;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) {
        // 模拟绘制多个圆形
        Circle redCircle1 = circleFactory.getCircle("红色");
        redCircle1.draw(10, 20); // 输出:绘制圆形 [颜色: 红色, 位置: (10, 20)]

        Circle redCircle2 = circleFactory.getCircle("红色");
        redCircle2.draw(30, 40); // 输出:绘制圆形 [颜色: 红色, 位置: (30, 40)]

        Circle blueCircle = circleFactory.getCircle("蓝色");
        blueCircle.draw(50, 60); // 输出:创建新圆形享元: 蓝色
                         // 输出:绘制圆形 [颜色: 蓝色, 位置: (50, 60)]
    }
}

这个案例通过 Spring Boot 的依赖注入,管理一个共享的 CircleFactory,用于创建和复用 CircleFlyweight 对象。CircleFlyweight 存储圆形的颜色作为内部状态,共享于相同颜色的圆形对象;位置坐标作为外部状态,由客户端在 draw 方法中传递。CircleFactory 维护一个享元池,通过 circleMap 缓存已创建的圆形对象,避免重复创建相同颜色的圆形。享元模式在这里显著减少了内存占用,特别适合需要创建大量相似对象的场景,同时通过 Spring 的 IoC 容器提升了代码的可维护性和扩展性。

总结

享元模式如同一位内存管理的艺术家,通过共享内部状态,将资源占用降至最低,为性能敏感的系统注入高效灵魂。在 Spring 中,BeanDefinition 的共享机制体现了享元模式的精髓,优化了 IoC 容器的内存使用。结合 Spring Boot,开发者可以轻松实现高性能的对象复用,应对复杂场景。掌握享元模式,不仅能写出内存高效的代码,更能设计出如 Spring 般优雅的系统架构,让每一字节都物尽其用。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢