Java设计模式之享元模式

发布于:2025-03-21 ⋅ 阅读:(17) ⋅ 点赞:(0)

概念

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

1.内部状态(Intrinsic):可共享的、不变的部分(如颜色)。

2.外部状态(Extrinsic):不可共享的、变化的部分(如位置、半径)。

作用

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

2.提高系统性能(对象初始化成本高时效果显著)。

使用场景

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); // 外部状态每次不同
        }
    }
}

优点和缺点

优点

1.减少内存使用。

2.提高性能(减少GC压力)。

3.适用于大量相似对象的场景。

缺点

1.增加系统复杂性。

2.需要区分内部/外部状态。

3.可能引入线程安全问题。

未使用享元模式的实现

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);
        }
    }
}

总结

1.享元核心:通过对象复用将对象数量从使用次数级别降低到不同状态组合级别。

2.取舍判断:当对象初始化成本高且存在大量重复状态时优先使用。

3.状态管理:需要仔细区分类的固有属性和运行时可变属性。

4.性能影响:在需要创建数百万个对象的场景中,内存节省效果会非常显著。

实际开发中,Java的String常量池、Integer.valueOf()缓存(-128~127)都是享元模式的经典应用。

享元模式和单例模式的区别

特征

享元模式

单例模式

核心目标

通过共享多个对象减少内存占用

确保全局唯一对象

对象数量

按内部状态分类创建多个共享对象

整个系统只存在一个实例

状态管理

区分内部状态(共享)和外部状态

通常不区分状态,或状态全局共享

创建方式

工厂根据参数返回不同共享对象

静态方法返回唯一实例

适用场景

需要管理大量相似对象的场景

需要全局唯一访问点的场景

典型应用

游戏粒子系统、文档编辑器字符对象

数据库连接池、配置管理器、日志工具