java设计模式学习之【享元模式】

news/2024/7/21 4:14:06 标签: java, 设计模式, 享元模式

文章目录

  • 引言
  • 享元模式简介
    • 定义与用途
    • 实现方式
  • 使用场景
  • 优势与劣势
  • 在Java中的应用
  • 享元模式在Spring中的应用
  • 画图示例
  • 代码地址

引言

想象一下,您正在开发一个游戏,游戏中有成千上万的树木和建筑。如果每个对象都独立存储它的所有数据,将会占用大量的内存资源。享元模式提供了一种优化的解决方案,它通过共享相似对象的共有部分,减少内存的使用,同时保持独立对象的特性。

享元模式简介

定义与用途

享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少创建大量相似对象的内存开销。它通过共享相似对象的共有状态,减少资源消耗,特别是在需要大量对象的情况下。

实现方式

实现享元模式通常包括以下几个关键组件:

  • 享元接口(Flyweight): 定义了享元对象的共有方法。
  • 具体享元(Concrete Flyweight): 实现享元接口,存储内部状态。
  • 享元工厂(Flyweight Factory): 创建并管理享元对象,确保合理地共享对象。

使用场景

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

  • 当一个应用程序需要大量的相似对象时,可以使用享元模式来减少内存消耗。
  • 当对象的大多数状态可以被外部化时,享元模式可以有效地共享数据。
  • 当需要细粒度对象来表示数据时,而且这些数据可以被共享。

例如:

  1. 游戏开发中的环境设计:如树木、草、石头等,可以共享相同的模型和纹理。
  2. 文本处理程序中的字符处理:字符实例可以被共享,以减少内存占用。
  3. 用户界面中的控件和图标:在整个应用中可以共享相同的图标或控件实例。

优势与劣势

  • 优势
    减少内存消耗: 通过共享相似对象,显著减少内存占用。
    提高性能: 减少对象创建和销毁的开销,提升应用性能。
  • 劣势
    增加系统复杂性: 需要维护共享对象的状态,可能增加系统的复杂性。
    外部状态管理: 享元对象的外部状态需要由客户端代码维护,可能增加客户端的负担。

在Java中的应用

在Java中,String常量池是享元模式的一个经典例子。Java虚拟机(JVM)中的String常量池存储了所有的字符串字面量。这些字符串字面量是共享的,从而节约了内存。

享元模式在Spring中的应用

在Spring框架中,享元模式的应用并不像一些其他设计模式那样显而易见,但它确实在一些关键部分发挥作用,特别是在优化性能和资源管理方面。以下是一些示例:

Spring Bean的作用域管理:在Spring框架中,Bean的作用域可以被定义为单例(Singleton),这实际上是享元模式的一种应用。在单例模式下,Spring容器为每个Bean定义创建一个唯一的实例,并在整个容器中共享这个实例。这种方式减少了对象的创建,从而节约资源和提高效率。

Spring Security的权限缓存:在Spring Security中,权限信息经常被缓存以提高性能。这些权限对象的实例在需要时被创建,并在多个上下文中共享,这就是一种享元模式的实现。通过共享相同的权限对象实例,Spring Security减少了对象的创建和内存占用。

资源池的实现:在Spring中,资源如数据库连接和线程池常常使用享元模式进行管理。这些资源被创建并存储在池中,当需要时可以被多个客户端共享和重用。这样的资源共享减少了资源的频繁创建和销毁,优化了性能。

缓存机制:Spring框架提供了缓存抽象,可以通过缓存共享经常访问的数据,减少对外部系统(如数据库)的访问。这种缓存策略的背后思想与享元模式相似,即重用已有对象来减少资源消耗和提高效率。

通过这些应用,Spring框架有效地实现了享元模式的核心思想:共享和重用对象,以减少资源消耗和提高应用性能。

画图示例

在这里插入图片描述
步骤 1: 创建图形一个接口。

java">public interface Shape {
    void draw();
}

步骤 2: 实现具体类,创建了 Circle 类,实现了 Shape 接口。这个类包含圆的属性,如颜色、坐标和半径。

java">public class Circle implements Shape {
   private String color;
   private int x;
   private int y;
   private int radius;

   public Circle(String color){
      this.color = color;		
   }

   // 省略了设置 x, y, radius 的方法

   @Override
   public void draw() {
      System.out.println("绘制圆形:[颜色 : " + color + ", x : " + x + ", y :" + y + ", 半径 :" + radius);
   }
}

步骤 3: 创建工厂类
ShapeFactory 类用于基于给定的信息(如颜色)生成 Circle 对象。它内部维护了一个 HashMap,用于缓存已经创建的 Circle 对象。

java">import java.util.HashMap;

public class ShapeFactory {

   private static final HashMap<String, Circle> circleMap = new HashMap<>();

   public static Shape getCircle(String color) {
      Circle circle = circleMap.get(color);

      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("创建颜色为 " + color + " 的圆形");
      }
      return circle;
   }
}

步骤 4: 使用工厂类
FlyweightPatternDemo 类演示了如何使用 ShapeFactory 来获取特定颜色的 Circle 实例。它演示了如何有效地重用已经创建的对象,而不是每次都创建新对象。

java">public class FlyweightPatternDemo {
   private static final String[] colors = { "红色", "绿色", "蓝色", "白色", "黑色" };

   public static void main(String[] args) {
      for(int i = 0; i < 20; ++i) {
         Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor());
         circle.setX(getRandomX());
         circle.setY(getRandomY());
         circle.setRadius(100);
         circle.draw();
      }
   }

   private static String getRandomColor() {
      return colors[(int)(Math.random() * colors.length)];
   }

   private static int getRandomX() {
      return (int)(Math.random() * 100);
   }

   private static int getRandomY() {
      return (int)(Math.random() * 100);
   }
}

在这里插入图片描述
这个示例中,ShapeFactory 充当享元工厂,管理 Circle 对象的创建和缓存。当请求特定颜色的圆时,工厂首先检查是否已经创建了该颜色的圆。如果已存在,则重用该对象;如果不存在,才创建新的圆,并将其存储在哈希表中以供将来重用。这种方式显著减少了对象创建的数量,从而优化了内存使用和性能。

代码地址

23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern


http://www.niftyadmin.cn/n/5260810.html

相关文章

[数据集][目标检测]道路坑洞目标检测数据集VOC+YOLO格式665张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;665 标注数量(xml文件个数)&#xff1a;665 标注数量(txt文件个数)&#xff1a;665 标注类别…

大数据机器学习与深度学习——过拟合、欠拟合及机器学习算法分类

大数据机器学习与深度学习——过拟合、欠拟合及机器学习算法分类 过拟合&#xff0c;欠拟合 针对模型的拟合&#xff0c;这里引入两个概念&#xff1a;过拟合&#xff0c;欠拟合。 过拟合&#xff1a;在机器学习任务中&#xff0c;我们通常将数据集分为两部分&#xff1a;训…

K8S(四)—pod详解

目录 pod介绍Pod的概念&#xff1a;Pod的特性&#xff1a;Pod的配置&#xff1a;Pod的控制&#xff1a;示例 YAML 文件&#xff1a; pod启动流程问题 两种方式启动镜像的升级和回滚更新 Deployment&#xff1a;回滚检查 Deployment 历史版本回滚到之前的修订版本缩放 Deploymen…

Java面试题(每天10题)-------连载(47)

目录 Mybatis篇 1、#{}和${}的区别 2、通常一个Xml映射文件&#xff0c;都会写一个Dao接口与之对应&#xff0c;那么这个Dao接口的工作原理是什么&#xff1f;Dao接口中的方法&#xff0c;参数不同时&#xff0c;方法能重载吗&#xff1f; 3、Mybatis是如何让进行分页的&am…

深度学习环境配置------windows系统(GPU)------Pytorch

深度学习环境配置------windows系统&#xff08;GPU&#xff09;------Pytorch 准备工作明确操作系统明确显卡系列 CUDA和Cudnn下载与安装1.下载2.安装 环境配置过程1.安装Anacoda2.配置环境1&#xff09;创建一个新的虚拟环境2&#xff09;pytorch相关库的安装 2.安装VScode1&…

electron命令下载失败,手动安装教程

现象&#xff1a;pnpm i electron, 一直卡在提示错误node install.js 一 、下载需要的electron版本 地址 二、下载完毕&#xff0c;解压压缩包&#xff0c; 进入项目的node_modules/electron文件夹&#xff0c;创建dist文件夹&#xff0c;将下载的zip包里的文件复制到dist…

mysql数据库相关知识【MYSQL】

mysql数据库相关知识【MYSQL】 一. 库1.1 登录数据库管理系统1.2 什么是数据库1.2.1 mysqld与mysql 1.3 编码集和校验集1.3.1 什么是编码集和校验集1.3.2 查看库对应的编码集和校验集1.3.3 用指定的编码集和校验集 1.4 库的操作 一. 库 1.1 登录数据库管理系统 这个算是第一个…

ARM MMU简介

MMU内存保护场景 ARM MMU能够针对多种场景进行内存保护&#xff0c;包括以下几个常见的例子&#xff1a; 1. 操作系统级别的内存隔离 ARM MMU可以将不同的进程或线程的虚拟地址映射到不同的物理地址空间&#xff0c;实现进程间的内存隔离。这样可以确保一个进程无法访问或篡…