前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「聊设计模式」之享元模式(Flyweight)

「聊设计模式」之享元模式(Flyweight)

原创
作者头像
bug菌
发布2023-11-10 00:04:19
1650
发布2023-11-10 00:04:19
举报
文章被收录于专栏:《项目实战教学》

🏆本文收录于聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


大家下午好,我是bug菌,今天我们继续聊设计模式。

前言

  设计模式是解决复杂问题的最佳实践之一,这些模式都是由经验丰富的程序员在解决问题中总结出来的。享元模式是一种结构型设计模式,旨在通过共享尽可能多的对象来减少内存使用和提高性能。

摘要

  享元模式是一个可用于优化重复性的设计模式。如果在应用程序中创建了大量相似的对象,那么可以使用享元模式来减少所需的内存和性能开销。该模式实现了对象的共享,从而减少了内存中对象的数量。也就是说,享元模式允许将对象的状态分为内部状态和外部状态。内部状态存储在享元对象内部,并且在对象创建之后不会发生变化。外部状态由客户端代码传递给享元对象。

享元模式

概念

  享元模式是一种结构型设计模式,它通过共享相同或相似的对象来减少内存消耗,提高系统的性能和效率。

  在享元模式中,对象分为两类:内部状态和外部状态。内部状态是对象的固有属性,可以被共享;而外部状态则取决于对象的使用环境,不可共享。享元模式将内部状态和外部状态分离,并共享内部状态,从而减少内存中相同状态对象的数量。

  典型的享元模式应用场景是在需要大量创建相同或相似对象,且创建和销毁对象的成本较高时,如数据库连接池、线程池等。通过共享已有的对象,减少新对象的创建,可以有效地优化系统性能和资源利用。

结构

享元模式中有以下几个角色:

  • 抽象享元(Flyweight):享元接口,声明了享元对象的方法。
  • 具体享元(ConcreteFlyweight):实现抽象享元接口,实现抽象享元的方法,并且需要注意内部状态和外部状态的处理。
  • 享元工厂(FlyweightFactory):享元工厂用于创建和管理享元对象,它维护一个享元池用于存储已经创建的享元对象,以便重复利用。
  • 客户端(Client):使用享元工厂创建和管理享元对象。

如下是享元模式的UML类图:

优缺点

优点:

享元模式的优点如下:

  • 享元模式可以大大减少内存使用,因为共享对象可以由多个上下文使用。它可以用于缓存那些不经常改变但经常使用的对象,从而提高系统的性能。
  • 通过使用享元模式,可以减少对象的数量,从而降低系统的复杂性。缺点:

享元模式的 缺点如下:

  • 实现享元模式需要对系统进行全面分析和重构,这可能会增加系统的开发时间和成本。
  • 如果内部状态非常复杂,并且不能分为内部状态和外部状态,那么享元模式将无法提供帮助。

应用场景

享元模式适用于以下场景:

  1. 当需要创建大量对象时,使用享元模式可以节省内存和系统资源,提高系统性能。
  2. 对象具有可共享的状态,因此可以将这些状态独立出来,让多个对象共享。例如,一个文本编辑器中的字符或字体颜色可以共享,从而减少内存占用。
  3. 享元模式可以用于缓存系统中,将经常使用的数据缓存起来,以减少系统的访问压力。
  4. 适用于使用少量对象来表示大量数据的情况,例如棋盘游戏中的棋子。
  5. 适用于需要合理控制内存使用和对象数量的场合,例如移动设备上的游戏开发。

总之,享元模式适用于需要创建大量相似对象的场景,通过共享对象的状态来减少内存占用,提高系统性能。

模式实现

  下面是一个简单的示例代码,展示如何使用享元模式来创建和管理汽车对象。

首先是抽象享元接口:

代码语言:java
复制
package com.example.javaDesignPattern.flyweight;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 16:15
 */
public interface Car {
    void drive(String location);
}

然后是具体享元实现:

代码语言:java
复制
package com.example.javaDesignPattern.flyweight;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 16:15
 */
public class Bike implements Car {
    private String type;

    public Bike(String type) {
        this.type = type;
    }

    @Override
    public void drive(String location) {
        System.out.println("Drive " + type + " bike to " + location);
    }
}
代码语言:java
复制
package com.example.javaDesignPattern.flyweight;

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

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 16:16
 */
public class CarFactory {
    private static Map<String, Car> carPool = new HashMap<>();

    public static Car getCar(String type) {
        Car car = carPool.get(type);

        if (car == null) {
            car = new Bike(type);
            carPool.put(type, car);
            System.out.println("Create new car of type " + type);
        }
        return car;
    }
}

客户端代码如下所示:

代码语言:java
复制
package com.example.javaDesignPattern.flyweight;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 16:16
 */
public class Client {
    public static void main(String[] args) {
        Car car1 = CarFactory.getCar("Sport");
        car1.drive("New York");

        Car car2 = CarFactory.getCar("Sport");
        car2.drive("San Francisco");

        Car car3 = CarFactory.getCar("Economy");
        car3.drive("Los Angeles");
    }
}

  在客户端代码中,我们使用工厂方法来创建汽车对象。如果工厂已经创建了某种类型的汽车,则从享元池中返回汽车对象。否则,它将创建一个新的汽车对象,并将其添加到享元池中。

代码方法介绍

Car

  • drive(String location) 方法:驾驶汽车到指定的位置。

Bike

  • Bike(String type) 构造方法:创建具体享元对象。
  • drive(String location) 方法:驾驶自行车到指定的位置。

CarFactory

  • getCar(String type) 方法:从享元池中获取指定类型的汽车对象。

Client

  • main(String[] args) 方法:客户端代码,用于测试享元模式。

测试用例

  下面是测试代码,用于测试享元模式是否工作正常。您可以在本地使用Java编译器运行该代码来查看它是否有效。

代码语言:java
复制
public class Client {
    public static void main(String[] args) {
        Car car1 = CarFactory.getCar("Sport");
        car1.drive("New York");

        Car car2 = CarFactory.getCar("Sport");
        car2.drive("San Francisco");

        Car car3 = CarFactory.getCar("Economy");
        car3.drive("Los Angeles");
    }
}

执行结果如下:

在这里插入图片描述
在这里插入图片描述

测试用例代码解析

  这段代码展示了工厂方法模式的示例。首先定义了一个Client类,其中main方法中创建了三个Car对象,分别使用了工厂方法CarFactory.getCar()来获取不同类型的车辆对象。然后分别调用了这些车辆对象的drive方法来模拟它们载客出行的场景。

  值得注意的是,工厂方法CarFactory.getCar()根据传入的参数来选择要创建的车辆对象的类型。在这个示例中,它接受的参数是字符串类型,对应着两种不同的车辆类型:SportEconomy。如果需要添加更多类型的车辆,只需要在工厂方法中加入对应的逻辑即可。这也是工厂方法模式的优点之一,它使得代码更加灵活,易于扩展。

小结

  享元模式是一种结构性设计模式,可用于优化内存使用和性能。通过将对象分为内部状态和外部状态,可以共享已经创建的对象实例。该模式适用于需要创建大量相似对象的应用程序。

附录源码

  如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。

总结

  享元模式可以帮助我们优化重复性的代码。它允许我们共享已经创建的相似对象,并且可以显著减少内存使用和性能开销。但是,实现此模式需要对系统进行全面分析和重构。如果可以正确地实现享元模式,那么它将有助于提高系统的性能和扩展性。

☀️建议/推荐你


  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

📣关于我

  我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。


我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 摘要
  • 享元模式
    • 概念
      • 结构
        • 优缺点
          • 优点:
        • 应用场景
          • 模式实现
            • 代码方法介绍
              • Car
              • Bike
              • CarFactory
              • Client
            • 测试用例
              • 测试用例代码解析
            • 小结
              • 附录源码
              • 总结
              • ☀️建议/推荐你
              • 📣关于我
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档