设计模式详解(十三)——享元模式

享元模式简介

享元模式定义
享元模式(Flyweight Pattern)是一种用于优化性能的软件设计模式。它是一种结构型的设计模式。它的主要目的是通过共享物件来减少内存使用量,同时分享信息给尽可能多的相似物件,从而降低内存消耗和提高系统性能。这种模式特别适用于那些因为重复而导致使用大量内存的大量物件。享元模式将对象的状态分为内部状态和外部状态,其中一些具有相同内部状态的对象可以被多个对象共享,而不是为每个对象都创建新的实例;而外部状态是变化的,不能共享。通过共享不变的部分,可以减少不必要的对象创建和内存消耗,提高系统性能。

享元模式包含以下角色:

  1. 抽象享元角色(Flyweight Interface):享元对象抽象了一个接口或抽象类,用于声明享元对象的方法。这些方法使得外部状态能够以参数形式传入。通常这个接口不会涉及到外部状态的具体细节,它仅仅关注于内部状态的操作。
  2. 具体享元角色(Concrete Flyweight):具体享元角色实现了抽象享元接口,并包含内部状态的存储。内部状态是享元对象可以共享的部分,具体享元角色可以被多个客户端对象共享。
  3. 享元工厂角色(Flyweight Factory):负责创建和管理享元对象。它维护了一个享元对象的缓存池,当客户端请求享元对象时,工厂会首先检查缓存池中是否存在具有相同内部状态的享元对象,如果存在则直接返回,否则创建一个新的享元对象并添加到缓存池中。
  4. 客户端角色(Client):持有对享元对象的引用,并负责在必要时通过享元工厂获取享元对象。客户端角色与享元对象交互,并可能提供外部状态给享元对象。

享元模式优缺点:
优点:

  1. 减少内存消耗:通过共享大量相似对象,可以减少系统中对象的数量,从而降低内存消耗。这在处理大量相似对象时尤为有效,可以显著提高系统的资源利用率。
  2. 性能提升:由于共享的对象可以被多个客户端共享,所以减少了对象的创建和销毁次数,享元模式可以提高系统的性能。特别是在频繁创建和销毁对象的场景中,享元模式能够显著减少这些操作带来的开销。
  3. 降低系统复杂性:享元模式将内部状态与外部状态是分离的状态,使得系统更容易理解和维护。内部状态由享元对象管理,外部状态由客户端管理,降低了系统的复杂性,可以有效地降低对象间的耦合度。

缺点:

  1. 增加编程复杂性:实现享元模式需要将对象的状态分为内部状态和外部状态,需要对内部状态和外部状态进行较为繁琐的区分这要求开发者对系统的状态管理有深入的理解。
  2. 增加系统的维护性:由于享元模式将对象的状态分为内部状态和外部状态,这可能会增加系统的复杂度,使得系统的维护变得困难。特别是在处理复杂的业务逻辑时,需要格外小心以确保状态的正确性和一致性。
  3. 降低代码的可读性:由于享元模式涉及到对对象状态的划分和共享,可能会使得代码的逻辑变得复杂,降低代码的可读性。这要求开发者在编写代码时注重注释和文档,以提高代码的可理解性。
  4. 可能引入线程安全问题:如果多个线程同时访问和修改共享对象,可能会导致线程安全问题。因此,在使用享元模式时,需要特别注意线程安全的处理。

使用场景

  1. 当程序中需要创建大量相似对象,并且这些对象可以共享一部分状态时,使用享元模式可以节省内存和提高性能。
  2. 当创建对象的成本较高,且对象的状态可以分为内部状态和外部状态时,可以考虑使用享元模式。内部状态可以由对象共享,而外部状态则通过参数传递给享元对象。这样可以减少创建对象的数量,提高系统的可扩展性和性能。
  3. 在需要处理大量数据的系统中,可能存在大量的重复对象。这些对象可以通过享元模式来共享,减少对象的创建和内存消耗,提高系统的性能和可扩展性。
  4. 在高并发的系统中,可能存在大量的请求和对象。通过享元模式共享对象,可以减少对象的创建和销毁,提高系统的并发处理能力和响应速度。

以下举一个享元模式的例子:
下面通过一个简单的例子来演示。将一辆小汽车可以看做是一个享元对象,共享的部分是小汽车的基本属性,比如颜色,发动机排量等。相同颜色、发动机排量的小汽车可以共享同一个对象,不需要每次创建新的对象。

创建抽象享元角色(Flyweight Interface)

public abstract class Car {
    protected String color;
    protected String engine;

    public Car(String color, String engine) {
        this.color = color;
        this.engine = engine;
    }

    public abstract void show();
}

创建具体享元角色(Concrete Flyweight)

public class BMW extends Car {
    public BMW(String color, String engine) {
        super(color, engine);
    }

    @Override
    public void show() {
        System.out.println("生产BMW汽车:颜色是" + color + ",发动机排量是" + engine);
    }
}
public class Benz extends Car{
    public Benz(String color, String engine) {
        super(color, engine);
    }

    @Override
    public void show() {
        System.out.println("生产Benz汽车:颜色是" + color + ",发动机排量是" + engine);
    }
}

创建享元工厂角色(Flyweight Factory)

import java.util.HashMap;
import java.util.Map;

public class CarFactory {
    public static Map<String, Car> carMap=new HashMap<>();
    public static Car getCar(String color,String type){
        String key=color+"_"+type;
        if(carMap.containsKey(key)){
            //如果已经有该颜色和类型的汽车,直接返回
            return carMap.get(key);
        }else {
            Car car = null;
            //没有,创建并放入缓存
            if("BMW".equals(type)){
                car = new BMW(color,"2.0L");
            }else if ("Benz".equals(type)){
                car = new Benz(color,"2.0L");
            }else {
                System.out.println("没有该类型的汽车");
            }
            //放入缓存
            carMap.put(key,car);
            return car;
        }
    }
}

创建客户端(Client)

public class Client {
    public static void main(String[] args) {
        Car bmwCar = CarFactory.getCar("白色", "BMW");
        Car benzCar = CarFactory.getCar("白色", "Benz");

        bmwCar.show();
        benzCar.show();
        System.out.println("现在已存在有" + CarFactory.carMap.size() + "种类型的汽车,及共享的相同对象");

        System.out.println("===================================");
        System.out.println("创建上面创建过的相同颜色和类型的汽车");
        Car bmwCar2 = CarFactory.getCar("白色", "BMW");
        bmwCar2.show();
        System.out.println("创建相同颜色和类型的汽车后,现在已存在有" + CarFactory.carMap.size() + "种类型的汽车,及共享的相同对象");

        System.out.println("===================================");
        System.out.println("创建上面没有添加过的颜色的汽车");
        Car bmwCar3 = CarFactory.getCar("黑色", "BMW");
        bmwCar3.show();
        System.out.println("创建不同的颜色,相同类型的汽车后,现在已存在有" + CarFactory.carMap.size() + "种类型的汽车,及共享的相同对象");
    }
}

输出结果如下所示:

生产BMW汽车:颜色是白色,发动机排量是2.0L
生产Benz汽车:颜色是白色,发动机排量是2.0L
现在已存在有2种类型的汽车,及共享的相同对象
===================================
创建上面创建过的相同颜色和类型的汽车
生产BMW汽车:颜色是白色,发动机排量是2.0L
创建相同颜色和类型的汽车后,现在已存在有2种类型的汽车,及共享的相同对象
===================================
创建上面没有添加过的颜色的汽车
生产BMW汽车:颜色是黑色,发动机排量是2.0L
创建不同的颜色,相同类型的汽车后,现在已存在有3种类型的汽车,及共享的相同对象

在上述例子中,我们共享了Car类,并在创建Car类时,设置了不同颜色。虽然我们创建了多次小汽车,但它们相同颜色和相同发动机排量的共享同一个享元对象,因此创建相同相同颜色和相同发动机排量的汽车时,可以减少了内存占用。

总而言之:
享元模式是一种用于优化性能的软件设计模式,它通过共享对象来减少内存中对象的数量,从而降低内存消耗并提高系统性能。该模式主要适用于大量相似对象、对象创建成本较高、需要精细化控制对象共享、大数据量处理、高并发以及分布式系统中的对象共享等场景。享元模式的优点包括减少内存消耗、提高性能以及支持大量细粒度对象。然而,它也可能增加编程的复杂性,并可能引入线程安全问题。因此,在选择使用享元模式时,需要仔细评估其适用性和潜在影响。享元模式是一种非常有用的设计模式,可以帮助我们优化系统性能并减少内存消耗。但是,它也需要在具体场景下仔细考虑和权衡利弊,确保正确使用并带来实际的效益。


以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

相关推荐

  1. 设计模式详解)——模式

    2024-04-08 10:26:02       36 阅读
  2. 设计模式

    2024-04-08 10:26:02       58 阅读
  3. 设计模式-模式

    2024-04-08 10:26:02       58 阅读
  4. 设计模式模式

    2024-04-08 10:26:02       39 阅读
  5. 设计模式模式

    2024-04-08 10:26:02       41 阅读
  6. 设计模式--模式

    2024-04-08 10:26:02       25 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-08 10:26:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-08 10:26:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-08 10:26:02       87 阅读
  4. Python语言-面向对象

    2024-04-08 10:26:02       96 阅读

热门阅读

  1. vue3 keep-alive include失效问题

    2024-04-08 10:26:02       37 阅读
  2. [Algorithm][双指针][复写零]详细解读 + 代码实现

    2024-04-08 10:26:02       43 阅读
  3. 比赛记录:Codeforces Global Round 25 A~E (猜猜题场)

    2024-04-08 10:26:02       29 阅读
  4. Solr面试题

    2024-04-08 10:26:02       33 阅读
  5. 缓存更新策略

    2024-04-08 10:26:02       34 阅读
  6. P1308 统计单词数

    2024-04-08 10:26:02       36 阅读
  7. 工业视觉AI应用总结记录

    2024-04-08 10:26:02       28 阅读