28 设计模式:享元模式-结构型模式

109 阅读4分钟

结构型模式之:

  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰模式
  • 代理模式
  • 享元模式
  • 外观模式

1.什么是享元模式、

享元模式是一种结构型设计模式,旨在通过共享尽可能多的对象来最小化内存使用和提高性能。在享元模式中,对象被分为可共享的内部状态和不可共享的外部状态。内部状态存储在享元对象内部,而外部状态则由客户端维护和传递给享元对象。

举一个简单的例子,假设我们有一个文本编辑器应用程序,需要在文本中显示大量的相同字符。在不使用享元模式的情况下,我们可能会为每个字符创建一个单独的对象,这会导致内存消耗过大。而使用享元模式,我们可以将相同字符的实例缓存起来并共享,从而减少内存消耗。

下面是一个简化的示例代码,展示了如何在Java中实现享元模式:

// 定义享元接口
interface TextCharacter {
    void draw(String color);
}

// 具体享元类
class Character implements TextCharacter {
    private char symbol;

    public Character(char symbol) {
        this.symbol = symbol;
    }

    @Override
    public void draw(String color) {
        System.out.println("Drawing " + symbol + " in " + color);
    }
}

// 享元工厂类
class CharacterFactory {
    private Map<Character, TextCharacter> characters = new HashMap<>();

    public TextCharacter getCharacter(char symbol) {
        TextCharacter character = characters.get(symbol);
        if (character == null) {
            character = new Character(symbol);
            characters.put(symbol, character);
        }
        return character;
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        CharacterFactory factory = new CharacterFactory();

        TextCharacter a = factory.getCharacter('A');
        TextCharacter b = factory.getCharacter('B');
        TextCharacter a2 = factory.getCharacter('A'); // 已经存在的字符,直接获取

        a.draw("red");
        b.draw("blue");
        a2.draw("green");
    }
}

在这个例子中,CharacterFactory 是享元工厂类,负责创建和管理享元对象。当客户端需要获取一个字符时,可以通过工厂类获取。如果字符已经存在于缓存中,则直接返回已有的实例,否则创建一个新的实例并缓存起来。通过这种方式,可以确保相同字符的实例在内存中只存在一份,从而节省内存空间。

2. 享元模式实际使用。

享元模式在实际框架中经常被用于优化系统的性能和资源利用率,特别是在处理大量相似对象时。以下是一些实际框架中享元模式的应用场景:

  1. 字符串池(String Pool):Java 中的字符串常量池就是享元模式的一个典型应用。字符串常量池存储了字符串字面量的唯一实例,当程序中存在相同的字符串字面量时,会直接引用常量池中的实例,避免了重复创建字符串对象,节省了内存空间。
  2. 数据库连接池:数据库连接池是常见的利用享元模式的例子。连接池维护了一组数据库连接的池子,当应用程序需要连接数据库时,可以从连接池中获取已经创建的连接,避免了频繁创建和销毁连接的开销,提高了数据库访问的效率。
  3. 图形界面组件:图形界面框架(如Swing、JavaFX等)中的组件对象,如按钮、文本框等,通常会存在大量相似的对象实例。使用享元模式,可以将那些不变的部分抽取出来作为共享部分,避免重复创建相同的组件对象,提高了系统的性能和响应速度。
  4. 缓存管理:在缓存系统中,可以使用享元模式来存储一些经常被访问的数据对象,例如网页缓存、图片缓存等。当用户请求相同的数据时,可以直接从缓存中获取,避免了频繁地从数据库或网络中读取数据,提高了系统的响应速度和吞吐量。

3. 享元模式的选择场景。

image.png

**仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式**。

应用该模式所获的收益大小取决于使用它的方式和情景。 它在下列情况中最有效

  • 程序需要生成数量巨大的相似对象
  • 这将耗尽目标设备的所有内存
  • 对象中包含可抽取且能在多个对象间共享的重复状态。

4. 享元模式的优缺点。

优点:

  • 如果程序中有很多相似对象, 那么你将可以节省大量内存

缺点:

  • 你可能需要牺牲执行速度来换取内存, 因为他人每次调用享元方法时都需要重新计算部分情景数据
  • 代码会变得更加复杂。 团队中的新成员总是会问: ​ “为什么要像这样拆分一个实体的状态?”