• 设计模式-享元模式(Flyweight)


    前言

    享元模式(Flyweight Pattern)是一种结构型设计模式,它的主要目标是减少应用程序中对象的数量,以节省内存和提高性能。这一模式适用于对象数量庞大且相似的情况,通过共享内部状态来减少对象的创建。

    在本篇博客中,我们将详细介绍享元模式的概念,并提供一个简单的Java代码示例来演示如何实现它。

    一、享元模式的概念

    享元模式的核心思想是将对象分为两种状态:内部状态(Intrinsic State)和外部状态(Extrinsic State)。内部状态是对象可以共享的部分,而外部状态是对象的特定部分,无法共享。通过将内部状态共享,我们可以大大减少对象的数量,从而减小内存占用和提高性能。

    二、 享元模式的结构

    享元模式包含以下主要组件:

    1. 享元接口(Flyweight):定义了享元对象的接口,包含一个操作方法,该方法需要外部状态作为参数。

    2. 具体享元类(ConcreteFlyweight):实现了享元接口,并包含了内部状态。具体享元对象通常是可共享的,因此可以被多个客户端共享。

    3. 享元工厂(Flyweight Factory):负责创建和管理享元对象。它通常包含一个享元对象池,用于缓存已创建的享元对象。

    4. 客户端(Client):使用享元对象的客户端。客户端需要维护外部状态,并在需要时将外部状态传递给享元对象。

    三、享元模式的优缺点

    享元模式(Flyweight Pattern)是一种有助于减少内存占用和提高性能的设计模式,但它也有其优点和缺点。让我们先来看一下享元模式的优点:

    1、优点

    1. 内存优化:享元模式通过共享对象实例来减少内存占用。对于具有大量相似对象的情况,这可以大幅度减小内存使用,提高应用程序的性能。

    2. 性能提升:由于共享的对象可以被多个客户端共享,因此可以减少对象的创建和销毁次数,从而提高了程序的性能。

    3. 降低系统复杂性:享元模式将内部状态与外部状态分离,使得系统更容易理解和维护。内部状态由享元对象管理,外部状态由客户端管理,降低了系统的复杂性。

    4. 可复用性:享元模式中的享元对象是可复用的,它们可以在不同上下文中被多次共享,从而提高了代码的可复用性。

    2、 缺点

    1. 引入复杂性:在享元模式中,需要维护共享池(或缓存)以管理共享对象的创建和销毁。这引入了额外的复杂性和开销。

    2. 不适用于所有情况:享元模式适用于具有大量相似对象的情况。对于对象数量不大或差异性很大的情况,引入享元模式可能会增加复杂性而不带来明显的好处。

    3. 可能导致线程安全问题:如果多个线程同时访问共享对象池,需要考虑线程安全问题。可能需要加锁或使用其他并发控制机制。

    4. 外部状态管理:外部状态由客户端维护,这可能会导致一些额外的复杂性和潜在的错误。客户端需要确保正确地传递外部状态,否则可能导致意外行为。

    3、 适用场景:

    享元模式在以下情况下特别适用:

    • 系统中存在大量相似对象,且占用大量内存。
    • 对象的状态可以被外部化,且可以在多个上下文中共享。
    • 对象的创建和销毁次数频繁,需要优化性能。
    • 需要分离对象的内部状态和外部状态,以便灵活地配置对象。

    在设计中,应该根据具体的问题和需求来考虑是否使用享元模式。该模式在合适的情况下可以带来显著的性能和内存占用优势,但不适用于所有情况。在应用享元模式时,需要仔细权衡其优点和缺点,并确保正确地实现和管理共享对象池。

    三、 享元模式的实现

    让我们通过一个简单的示例来演示享元模式的实现。我们将创建一个文本编辑器,其中字符是享元对象,可以在不同位置重复使用。

    首先,我们定义享元接口 Character

    interface Character {
        void display(int position);
    }
    
    • 1
    • 2
    • 3

    然后,创建具体享元类 ConcreteCharacter

    class ConcreteCharacter implements Character {
        private char character;
    
        public ConcreteCharacter(char character) {
            this.character = character;
        }
    
        @Override
        public void display(int position) {
            System.out.println("Character " + character + " is displayed at position " + position);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    接下来,我们创建享元工厂 CharacterFactory,用于管理和共享字符对象:

    class CharacterFactory {
        private Map<Character, Character> characterPool = new HashMap<>();
    
        public Character getCharacter(char c) {
            if (!characterPool.containsKey(c)) {
                characterPool.put(c, new ConcreteCharacter(c));
            }
            return characterPool.get(c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    最后,我们创建客户端 TextEditor,演示如何使用享元对象:

    public class TextEditor {
        public static void main(String[] args) {
            CharacterFactory factory = new CharacterFactory();
    
            Character a = factory.getCharacter('A');
            Character b = factory.getCharacter('B');
            Character c = factory.getCharacter('A');
    
            a.display(1);
            b.display(2);
            c.display(3);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这个示例中,我们共享了字符 ‘A’,并在不同位置显示它。虽然我们创建了多次字符 ‘A’,但它们都共享同一个享元对象,从而减少了内存占用。

    总结

    享元模式是一种有助于减少内存占用和提高性能的设计模式,特别适用于需要大量相似对象的情况。通过将内部状态进行共享,可以有效地减少对象的创建数量,提高了系统的效率。但需要注意,享元模式也增加了代码的复杂性,因为需要维护内部状态和外部状态的分离。因此,在选择是否使用享元模式时,需要根据具体的应用场景进行权衡。

  • 相关阅读:
    缺少 Google API 密钥,因此 Chromium 的部分功能将无法使用
    关于ETL的两种架构(ETL架构和ELT架构)
    【无标题】
    Spring循环依赖大全
    力扣labuladong——一刷day04
    VR禁毒教育 | 毒品认知VR虚拟仿真科普:提高青少年抵制毒品的意识和能力
    柔性作业车间调度问题-遗传算法求解方法
    [数据结构]八大排序算法总结
    好的内容回复区
    J2EE基础-自定义MVC(上)
  • 原文地址:https://blog.csdn.net/yanghezheng/article/details/132790251