Java设计模式-享元设计模式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 1. 享元设计模式介绍
    • 1.1 定义
    • 1.2 原理
    • 1.3 使用场景
    • 1.4 注意事项
  • 2. 享元设计模式角色
    • 2.1 抽象享元角色(‌AbstractFlyWeight)‌
    • 2.2 具体享元角色(‌ConcreteFlyWeight)‌
    • 2.3 享元工厂角色(‌FlyWeightFactory)‌
    • 2.4 客户端角色(‌Client)‌
  • 3. 享元设计模式优点
    • 3.1 减少内存使用
    • 3.2 提升性能
    • 3.3 简化操作
  • 4. 享元设计模式示例
    • 4.1 编写抽象享元角色(Shape.java)‌
    • 4.2 编写具体享元角色(Line.java和Oval.java)
    • 4.3 编写享元工厂角色(ShapeFactory.java)
    • 4.4 编写客户端示例代码
  • 2. 总结


在这里插入图片描述

1. 享元设计模式介绍

1.1 定义

享元模式(英语:Flyweight Pattern)是一种软件设计模式,属结构型设计模式。类似于外观模式适配器模式装饰模式

1.2 原理

享元模式通过共享已经存在的对象来减少对象的创建数量,‌从而节省系统资源,‌提高系统性能。‌这种模式特别适用于大量相似对象的场景,‌通过内部状态和外部状态的区分,‌实现了对象的复用和高效管理。‌

1.3 使用场景

当我们需要创建大量类的对象时,可以使用享元设计模式。由于每个对象都会占用内存空间,而这对于低内存设备(如移动设备或嵌入式系统)来说至关重要,因此可以应用享元设计模式,通过共享对象来减少内存负载

要应用享元模式,我们需要将对象属性分为内在属性外在属性内在属性使对象独一无二,而外在属性由客户端代码设置并用于执行不同的操作。例如,对象 Circle 可以具有外在属性,例如颜色和宽度。要应用享元模式,我们需要创建一个返回共享对象的享元工厂。

1.4 注意事项

在应用享元设计模式之前,我们需要考虑以下因素:

  • 应用程序要创建的对象数量应该非常庞大
  • 对象的创建会占用大量内存并且也很耗时。
  • 对象属性可以分为内在属性外在属性,对象的外在属性应该由客户端程序定义。

2. 享元设计模式角色

在这里插入图片描述

享元设计模式包含四个主要角色:‌

2.1 抽象享元角色(‌AbstractFlyWeight)‌

这个角色为具体享元角色规定了必须实现的方法,‌在Java中可以是抽象类或接口。‌它定义了享元对象的接口,‌但不涉及具体的实现细节。‌

2.2 具体享元角色(‌ConcreteFlyWeight)‌

这个角色实现了抽象享元角色定义的方法。‌如果存在内蕴状态,‌具体享元角色还负责为内蕴状态提供存储空间。‌

2.3 享元工厂角色(‌FlyWeightFactory)‌

这个角色负责创建和管理享元对象。‌它提供一个用于存储享元对象的享元池。‌当用户需要对象时,‌享元工厂首先尝试从享元池中获取对象。‌如果享元池中不存在所需对象,‌则创建一个新的享元对象并返回给用户,‌同时在享元池中保存该新增对象。‌

2.4 客户端角色(‌Client)‌

这个角色维护对所有享元对象的引用,‌并存储对应的外蕴状态。‌它使用享元工厂来生成抽象享元角色,‌是享元模式的最终使用者。‌

3. 享元设计模式优点

3.1 减少内存使用

享元模式通过共享对象来减少系统中的对象数量,‌从而节省内存空间。‌这是因为通过共享相同或相似的对象,‌避免了不必要的对象创建,‌减少了内存的消耗12。‌

3.2 提升性能

由于减少了对象的数量,‌系统性能得到了提高。‌这是因为共享对象可以避免重复创建对象的开销,‌使得系统运行更加高效12。‌

3.3 简化操作

对于具有相同或相似内部状态的对象,‌可以共享一个享元对象,‌简化了对对象的操作。‌这有助于减少代码复杂度,‌使得维护和扩展更加容易。‌

在这里插入图片描述

4. 享元设计模式示例

在下面的例子中,假设我们需要创建一个带有线条和椭圆的图形。因此,我们将有一个接口Shape及其具体实现LineOvalOval 类将具有内在属性来确定是否用给定的颜色填充椭圆,而 Line 则没有任何内在属性。

4.1 编写抽象享元角色(Shape.java)‌

import java.awt.Color;
import java.awt.Graphics;public interface Shape {public void draw(Graphics g, int x, int y, int width, int height,Color color);
}

4.2 编写具体享元角色(Line.java和Oval.java)

Line.java

import java.awt.Color;
import java.awt.Graphics;public class Line implements Shape {public Line(){System.out.println("Creating Line object");//adding time delaytry {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void draw(Graphics line, int x1, int y1, int x2, int y2,Color color) {line.setColor(color);line.drawLine(x1, y1, x2, y2);}
}

Oval.java
请注意,我特意引入了创建具体类的对象时的延迟,以表明享元模式可以用于实例化时需要大量时间的对象。

import java.awt.Color;
import java.awt.Graphics;public class Oval implements Shape {//intrinsic propertyprivate boolean fill;public Oval(boolean f){this.fill=f;System.out.println("Creating Oval object with fill="+f);// 添加一个延迟try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void draw(Graphics circle, int x, int y, int width, int height,Color color) {circle.setColor(color);circle.drawOval(x, y, width, height);if(fill){circle.fillOval(x, y, width, height);}}
}

4.3 编写享元工厂角色(ShapeFactory.java)

客户端程序将使用 flyweight 工厂来实例化对象,因此我们需要在工厂中保留一个对象映射,客户端应用程序不应访问该映射。每当客户端程序调用以获取对象实例时,它都应从 HashMap 返回,如果没有找到,则创建一个新对象并将其放入 Map 中,然后返回它。我们需要确保在创建对象时考虑所有内在属性。我们的 flyweight 工厂类如下所示。
ShapeFactory.java

import java.util.HashMap;public class ShapeFactory {private static final HashMap<ShapeType,Shape> shapes = new HashMap<ShapeType,Shape>();public static Shape getShape(ShapeType type) {Shape shapeImpl = shapes.get(type);if (shapeImpl == null) {// 没有找到,则实例化if (type.equals(ShapeType.OVAL_FILL)) {shapeImpl = new Oval(true);} else if (type.equals(ShapeType.OVAL_NOFILL)) {shapeImpl = new Oval(false);} else if (type.equals(ShapeType.LINE)) {shapeImpl = new Line();}// 将实例化的对象添加到shapes hash缓存中 ,方便下次快速获取,提高性能shapes.put(type, shapeImpl);}return shapeImpl;}public static enum ShapeType{OVAL_FILL,OVAL_NOFILL,LINE;}
}

4.4 编写客户端示例代码

下面是一个使用享元模式实现的示例程序。
DrawingClient.java

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;import com.journaldev.design.flyweight.ShapeFactory.ShapeType;public class DrawingClient extends JFrame{private static final long serialVersionUID = -1350200437285282550L;private final int WIDTH;private final int HEIGHT;private static final ShapeType shapes[] = { ShapeType.LINE, ShapeType.OVAL_FILL,ShapeType.OVAL_NOFILL };private static final Color colors[] = { Color.RED, Color.GREEN, Color.YELLOW };public DrawingClient(int width, int height){this.WIDTH=width;this.HEIGHT=height;Container contentPane = getContentPane();JButton startButton = new JButton("Draw");final JPanel panel = new JPanel();contentPane.add(panel, BorderLayout.CENTER);contentPane.add(startButton, BorderLayout.SOUTH);setSize(WIDTH, HEIGHT);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setVisible(true);startButton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent event) {Graphics g = panel.getGraphics();for (int i = 0; i < 20; ++i) {Shape shape = ShapeFactory.getShape(getRandomShape());shape.draw(g, getRandomX(), getRandomY(), getRandomWidth(),getRandomHeight(), getRandomColor());}}});}private ShapeType getRandomShape() {return shapes[(int) (Math.random() * shapes.length)];}private int getRandomX() {return (int) (Math.random() * WIDTH);}private int getRandomY() {return (int) (Math.random() * HEIGHT);}private int getRandomWidth() {return (int) (Math.random() * (WIDTH / 10));}private int getRandomHeight() {return (int) (Math.random() * (HEIGHT / 10));}private Color getRandomColor() {return colors[(int) (Math.random() * colors.length)];}public static void main(String[] args) {DrawingClient drawing = new DrawingClient(500,600);}
}

我使用随机数生成在我们的框架中生成不同类型的形状。如果您运行上述客户端程序,您会注意到在创建第一个线对象和椭圆对象时出现延迟,其中填充为真和假。之后,由于使用共享对象,程序执行速度很快。多次单击“绘制”按钮后,框架如下图所示。

在这里插入图片描述
您将在命令行中看到以下输出,确认对象是共享的。

Creating Line object
Creating Oval object with fill=true
Creating Oval object with fill=false

2. 总结

在这里插入图片描述
享元模式适用于存在大量相似对象的场景,‌特别是当对象的内部状态较少并且可以共享时。‌这种模式通过内部状态和外部状态的分离,‌使得外部状态的改变可以在外部进行设置,‌尽管这可能会带来一定的复杂性,‌但总体而言,‌享元模式在处理大量相似对象时表现出色。‌

以上就是关于享元模式的全部内容,我们将在以后的文章中探讨更多设计模式。如果您喜欢它,请在评论部分分享您的想法并与其他人分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/397418.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】视图——视图、视图的概念、为什么要使用视图、视图的基本使用、视图规则和限制

文章目录 MySQL1. 视图1.1 视图的概念1.2 为什么要使用视图1.3 视图的基本使用1.4 视图规则和限制 MySQL 1. 视图 1.1 视图的概念 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表…

【动态规划】1、不同路径II+2、三角形最小路径和

1、不同路径II&#xff08;难度中等&#xff09; 该题对应力扣网址 AC代码 只会写简单的if-else class Solution { public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {//1、定义子问题//2、子问题递推关系//3、确定dp数组的计算顺序…

uniapp获取swiper中子组件的内容高度

swiper有默认高度,如果不单独设置一个具体高度&#xff0c;swiper后面的内容将不会展示 这里展示的例子是: swiper中放有一个子组件,想要完整展示子组件的内容&#xff0c;swiper就需要获取到子组件的内容高度并设置 <!-- 注意: 这里的单位是 px,不是rpx --><swiper…

Element UI导航菜单刷新就复原问题解决方法~

1、首先要知道为什么一刷新就复原了&#xff0c;是因为default-active属性设置的是默认值&#xff0c;是一个死值&#xff0c;一旦刷新就会复原&#xff0c;造成高亮不能保持&#xff0c;那么怎么解决呢&#xff1f; 2、很简单&#xff0c;无需像一些博主一样绑定path。思路&a…

linux中信号的相关概念

信号 内核层和用户层通信的一种方式 信号类型 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18…

【限流与Sentinel超详细分析】

Sentinel 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件&#xff0c;主要以流量为切入点&#xff0c;从流量控制、熔断降级、系统自适应保护等多个维度来保障微服务的稳定性。 1 Sentinel 基本概念 资源…

MySQL —— 聚合查询,分组查询 与 联合查询

聚合函数 常见的统计总数、计算平局值等操作&#xff0c;可以使用聚合函数来实现&#xff0c;常见的聚合函数有&#xff1a; 函数说明count()统计数据总数sum()求和avg()求平均值max()求最大值min()求最小值 注意凡是涉及运算的&#xff0c;数据库会自动掉 NULL 值 注意NULL …

本地安Stable Diffusion全记录

这里写自定义目录标题 资料 资料 AI绘图软件Stable Diffusion 之本地安装 手把手教你在本机安装Stable Diffusion秋叶整合包 让 stable diffusion 局域网访问&#xff1a;详细解析配置步骤【Stable Diffusion 实战教程】 局域网多设备访问stable diffusion Stable Diffusion 老…

Lua语言基础学习:安装Lua和Lua库管理工具

Lua语言简介 Lua是一种轻量、高效、可嵌入的脚本语言&#xff0c;由巴西里约热内卢天主教大学的研究小组于1993年开发&#xff0c;Lua的解释器非常小巧&#xff0c;编译后的体积很小&#xff08;如完整解释器不过200KB&#xff09;&#xff0c;这使得它非常适合嵌入到其他应用程…

谷粒商城实战笔记-126-全文检索-ElasticSearch-整合-测试保存

文章目录 一&#xff0c;谷粒商城实战笔记-126-全文检索-ElasticSearch-整合-测试保存1&#xff0c;在Elasticsearch的配置类中增加通用设置2&#xff0c;索引数据3&#xff0c;验证 一&#xff0c;谷粒商城实战笔记-126-全文检索-ElasticSearch-整合-测试保存 1&#xff0c;在…

汇编语言基础及常见汇编指令

一、实验原理 x64dbg 是一款开源且免费的 Ring 3 级动态调试器&#xff0c;采用 QT 编写&#xff0c;支持 32 / 64 位程序。其反汇编引擎 BeaEngine 和 Capstone 功能极其强大&#xff0c;也有丰富的插件和脚本功能&#xff0c;且并保持更新&#xff0c;目前已经基本替代了 Ol…

数字医学影像系统PACS源码,三甲以下医院都能满足,C#语言开发,C/S架构系统成熟稳定,支持二次开发项目使用。

数字医学影像系统&#xff08;RIS/PACS&#xff09;源码&#xff0c;三甲以下的医院都能满足。开发技术&#xff1a;C/S架构&#xff0c;C#开发语言&#xff0c;数据库服务器采用Oracle数据库。 PACS系统模块组成 &#xff1a; 工作站&#xff1a; 分诊工作站、超声工作站、放…

学习鸿蒙-应用市场申请签名

1.需要的文件概念 .cer / .p7b / .p12 / .csr HarmonyOS应用/服务通过数字证书&#xff08;.cer文件&#xff09;和Profile文件&#xff08;.p7b文件&#xff09;来保证应用/服务的完整性。在申请数字证书和Profile文件前&#xff0c;首先需要通过DevEco Studio来生成密钥&am…

为具有公网IPV6地址的服务器安装nextcloudAIO并使用NginxProxyManager配置反向代理

软件和硬件环境 ubuntu server 24.04&#xff0c;并已配置好ipv6公网地址&#xff0c;已安装好docker和docker-compose。一块单独的硬盘&#xff0c;用于单独存储nextcloud数据。&#xff08;非必需&#xff09;有一个能够正常解析的域名&#xff0c;并已配置好AAAA记录解析。…

【Linux学习】动静态库从原理到制作

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f351;动静态库&#x1f41f;动静态库的制作与使用&#x1f680;生成静态库&#x1f512;生成动态库 &#x1f98c;动态库的查…

Maven下载、配置以及IDEA配置Maven新建Maven项目(超详细版)

Maven下载配置&#xff1a; 一、下载apache-maven-3.5.2并解压 二、创建一个本地仓库 三、在解压文件中的conf文件夹中的settings.xml文件中配置本地仓库 四、环境变量配置 1.此电脑(右击)------->属性------->高级系统设置------->环境变量 2.新建MAVEN_HOME&…

IP实现https访问的教程

IP地址实现HTTPS地址访问&#xff0c;首先要获得浏览器可信的SSL证书&#xff0c;并且该SSL证书是操作系统默认根证书信任证书。那有的人问&#xff1a;“内网的IP地址可以吗&#xff1f;答案是肯定不可以的”内网的IP地址只能用自建发的SSL证书实现HTTPS&#xff0c;不会被浏览…

数据结构——栈(Stack)

目录 前言 一、栈的概念 1、栈的基本定义 2、栈的特性 二、栈的基本操作 1.相关操作概念 2.实现方式 &#xff08;1&#xff09;顺序栈 &#xff08;2&#xff09;链式栈 三、栈的应用 总结 前言 栈&#xff08;Stack&#xff09;是一种常见且重要的数据结构&#xff0c;它遵循…

“tcp控制协议”的理解

情景解释&#xff1a; 1.过程&#xff1a; 在用户进行网络间通信时&#xff0c;不管是客户端还是服务端&#xff0c;都会有两个缓冲区——发送缓冲区和接受缓冲区。 通过4个缓冲区进行数据交流。 用户通过write()将数据发送到他的发送缓冲区中&#xff0c;再传输到服务端的…

C# Winform 多窗体切换方式一

一、简介 在 Winform 开发中&#xff0c;多窗体的切换是一个常见的需求&#xff0c;比如登录成功后&#xff0c;切换至主界面&#xff0c;在网上查阅相关的资料&#xff0c;你会发现很多都是用 form2.Show(); this.Hide(); 这种方式&#xff0c;这种方式也存在一些问题&#…