# 享元模式

# 概念

享元模式是一种结构型设计模式,通过共享对象来减少内存占用和对象创建开销。其核心思想是将对象状态分为两类:

1.内部状态(Intrinsic):可共享的、不变的部分(如颜色),存储在享元对象内部。

2.外部状态(Extrinsic):不可共享的、变化的部分(如位置、半径),由客户端在调用时传递。

# 作用

1.减少重复对象的创建,显著降低内存消耗。

2.提升系统性能,尤其在对象初始化成本较高时效果明显。

3.适用于需要管理大量相似对象的场景,通过对象复用优化资源。

# 场景

1.系统需要创建大量相似对象(如游戏中的粒子系统、文档编辑器中的字符对象)。

2.对象的大部分状态可以外部化(即状态可分离为内部共享部分和外部变化部分)。

3.需要缓存或对象池的场景(如网络请求复用、图形渲染中的基础元素复用)。

# 举例

以下是享元模式的典型实现代码:

// 享元接口
interface Circle {
    void draw(int x, int y, int radius);
}
// 具体享元类
class ConcreteCircle implements Circle {
    private final String color; // 内部状态(共享)

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

    @Override
    public void draw(int x, int y, int radius) { // 外部状态作为参数
        System.out.printf("Drawing %s circle at (%d,%d) with radius %d\n", 
                         color, x, y, radius);
    }
}
// 享元工厂
class CircleFactory {
    private static final Map<String, Circle> circleMap = new HashMap<>();

    public static Circle getCircle(String color) {
        // 如果没有生成特定颜色的圆,则生成并保存,最后再返回
        if (!circleMap.containsKey(color)) {
            Circle newCircle = new ConcreteCircle(color);
            circleMap.put(color, newCircle);
        } 
        return circleMap.get(color);
    }
}
// 客户端使用
public class Client {
    public static void main(String[] args) {
        String[] colors = {"Red", "Blue", "Green"};
        
        // 获取10个圆形,但实际只创建3个对象
        for(int i=0; i<10; i++){
            String color = colors[i % 3];
            Circle circle = CircleFactory.getCircle(color);
            circle.draw(i*10, i*20, 5); // 外部状态每次不同
        }
    }
}

# 反例

未使用享元模式时,每次创建对象都会生成新实例,导致内存浪费:

// 未使用享元的简单圆形类
class SimpleCircle {
    private String color;
    
    public SimpleCircle(String color) {
        this.color = color;
    }
    
    public void draw(int x, int y, int radius) {
        System.out.printf("Drawing %s circle at (%d,%d) with radius %d\n", 
                         color, x, y, radius);
    }
}
// 客户端使用(每次创建新对象)
public class Client {
    public static void main(String[] args) {
        String[] colors = {"Red", "Blue", "Green"};
        
        // 每次都会创建新对象(共创建10个对象)
        for(int i=0; i<10; i++){
            String color = colors[i % 3];
            SimpleCircle circle = new SimpleCircle(color); // 每次都新建对象
            circle.draw(i*10, i*20, 5);
        }
    }
}

# 原理

享元模式的核心是通过对象复用,将对象数量从“使用次数级别”降低到“不同内部状态组合级别”。例如,上述例子中10次调用仅创建3个对象(对应3种颜色),而非10个。其本质是区分对象的固有属性(内部状态)和运行时可变属性(外部状态),通过工厂模式管理共享对象的生命周期。

# 缺点

1.增加系统复杂性:需明确区分内部状态和外部状态,设计难度提升。

2.状态管理要求高:需确保内部状态真正不可变,外部状态正确传递,否则可能引发逻辑错误。

3.线程安全问题:共享对象在多线程环境下需额外同步机制,否则可能引发并发问题。

总结

享元模式通过共享对象优化内存使用,适用于大量相似对象的场景。其关键在于正确区分内部状态(共享)和外部状态(动态传递),并通过工厂模式管理共享实例。实际开发中,Java的String常量池、Integer.valueOf()缓存(-128~127)均为享元模式的经典应用。



微信公众号

QQ交流群
原创网站开发,偏差难以避免。

如若发现错误,诚心感谢反馈。

愿你倾心相念,愿你学有所成。

愿你朝华相顾,愿你前程似锦。