设计模式之享元模式:看19路棋盘如何做到一子千面

在这里插入图片描述

~犬📰余~

“我欲贱而贵,愚而智,贫而富,可乎?
曰:其唯学乎”

一、享元模式概述

\quad 在软件设计中,享元模式(Flyweight Pattern)的核心思想是通过共享来有效地支持大量细粒度对象的重用。这里的"享"体现在共享,"元"则体现在这些可以共享的基本元素上。正如共享单车系统一样,享元模式会维护一个对象池,其中存储可以复用的对象,当需要时直接从池中获取,而不是重新创建。
在这里插入图片描述
\quad 上图展示了享元模式的基本架构,我们可以看到多个客户端都在复用对象池中的共享对象。这些共享对象具有两种状态:

  • 内部状态:对象可共享的、固定不变的属性,就像自行车的基本构造。
  • 外部状态:对象不可共享的、随环境改变的属性,就像自行车的位置和使用状态。

\quad 这种模式特别适合处理需要创建大量相似对象的场景。通过识别对象的内部状态和外部状态,将可共享的部分集中管理,不仅可以显著减少内存占用,还能提升系统性能。

二、享元模式分类

\quad 在享元模式中,根据对象是否可以共享,我们可以将享元分为两种类型:共享享元和非共享享元,就像上图所展示的那样。

  • 共享享元是享元模式的核心,它代表那些可以被多个环境共享使用的对象。这类对象的特点是它们的内部状态是一致的,不会因为使用环境的改变而改变。就像围棋中的黑白棋子,每个黑棋的颜色和形状都是完全相同的,我们没必要为每个位置都创建新的棋子对象,而是可以共享使用现有的棋子,只需要改变它们的位置信息即可。
  • 非共享享元则是那些不能被共享的对象。这类对象可能具有特定的、不可共享的状态。虽然它们不共享,但仍然可以通过享元工厂来统一管理。比如在文字编辑器中,每个字符的字体样式可能都不相同,这时就需要使用非共享享元来处理这些特殊情况。

\quad 共享享元和非共享享元经常一起使用,它们各自处理不同的业务场景。共享享元主要用于那些需要大量创建相似对象的场景,通过共享来减少内存占用;而非共享享元则用于处理那些虽然结构相似,但状态必须独立的对象。

三、享元模式角色组成

图片
\quad 如上图所示,享元模式主要由四个核心角色组成,它们共同协作来实现对象的高效共享和管理。

  • Flyweight(享元接口)是所有具体享元类的公共接口,它定义了享元对象需要实现的方法。这个接口通常包含一个传入外部状态的操作方法,使享元对象能够根据外部状态改变其行为。
  • ConcreteFlyweight(具体享元类)是实现了Flyweight接口的具体类。它包含内部状态,也就是那些可以共享的、不会随环境改变的信息。例如,在围棋程序中,棋子的颜色就是内部状态。这个类的实例会被多个客户端共享使用。
  • UnsharedConcreteFlyweight(非共享具体享元类)也实现了Flyweight接口,但它的实例不会被共享。这个类包含了不能共享的状态信息。比如在文本编辑器中,虽然字符’A’可以被共享,但如果这个’A’有特殊的样式,就需要使用非共享享元来处理。
  • FlyweightFactory(享元工厂)负责创建和管理享元对象。它通常维护一个享元池(用Map实现),用于存储已创建的享元对象。当客户端请求一个享元对象时,工厂会先检查池中是否存在满足要求的对象,如果存在就直接返回,否则才创建新的对象。这保证了相同内部状态的享元对象只会被创建一次。

四、享元模式案例

\quad 让我们通过实现一个简单的围棋程序来深入理解享元模式。在围棋中,棋子只有黑白两色,但要放置在棋盘的不同位置上。这里棋子的颜色就是内部状态,可以被共享;而位置则是外部状态,需要在使用时指定。
图片
\quad 首先定义棋子的位置类:

// 棋子位置类-外部状态
public class Position {private int x;private int y;public Position(int x, int y) {this.x = x;this.y = y;}public int getX() { return x; }public int getY() { return y; }
}

\quad 接下来定义围棋的棋子共享接口以及实现类:

// 围棋棋子接口
public interface GoChessPiece {void display(Position position);
}
// 具体的围棋棋子类
public class ConcreteChessPiece implements GoChessPiece {private String color; // 内部状态public ConcreteChessPiece(String color) {this.color = color;}@Overridepublic void display(Position position) {System.out.printf("棋子颜色:%s,位置:(%d, %d)%n", color, position.getX(), position.getY());}
}

\quad 然后是工厂类:

import java.util.HashMap;
import java.util.Map;public class GoChessPieceFactory {private static final Map<String, GoChessPiece> pieces = new HashMap<>();public static GoChessPiece getChessPiece(String color) {GoChessPiece piece = pieces.get(color);if (piece == null) {piece = new ConcreteChessPiece(color);pieces.put(color, piece);}return piece;}
}

\quad 使用示例:

public class Client {public static void main(String[] args) {// 获取白色棋子并放在(2, 3)位置GoChessPiece white1 = GoChessPieceFactory.getChessPiece("白色");white1.display(new Position(2, 3));// 获取另一个白色棋子放在(3, 6)位置GoChessPiece white2 = GoChessPieceFactory.getChessPiece("白色");white2.display(new Position(3, 6));// 判断是否是同一个对象System.out.println("两个白棋是否共享同一个对象:" + (white1 == white2));}
}

\quad 测试结果:
在这里插入图片描述
\quad 在这个案例中,我们可以看到:

  1. 棋子的颜色(内部状态)被共享,每种颜色的棋子只会创建一个对象

  2. 棋子的位置(外部状态)在使用时由客户端指定

五、享元模式优缺点

优点

\quad 享元模式的核心优势是通过共享对象来减少内存占用,特别适合需要创建大量相似对象的场景。使用享元模式可以集中管理可复用的对象,使得对象的创建和维护更加规范和高效。

缺点

\quad 这种模式增加了系统的复杂度,需要额外的工厂类来管理对象池,同时还需要仔细区分内部状态和外部状态。在对象数量较少的场景下,这种模式带来的收益可能无法抵消其带来的开发成本。

六、享元模式适用场景

\quad 享元模式最适合应用在系统需要创建大量相似对象,且这些对象可以分离出共享部分的场景。典型的应用场景包括:

  • 文字编辑器中的字符渲染:相同的字符可以共享字形信息,只需要改变位置和样式
  • 游戏中的素材管理:相同的游戏素材(如树木、建筑)可以在不同位置重复使用
  • 地图应用中的图标:相同类型的地标可以共享图标资源
  • 网页中的图片缓存:相同的图片可以在多处被重复使用

\quad 当系统中存在大量重复对象,且这些对象的大部分状态都可以外部化时,使用享元模式可以显著降低内存占用并提高性能。

七、总结

\quad 享元模式通过对象共享来提高系统性能,是一种以时间换空间的设计模式。它将对象的状态分为内部状态和外部状态,通过共享内部状态来减少对象创建。在实现时,需要通过享元工厂来统一管理对象池,确保相同内部状态的对象只被创建一次。这种模式特别适合需要大量创建相似对象的场景,但在使用时需要权衡其带来的复杂性和收益。

在这里插入图片描述

关注犬余,共同进步

技术从此不孤单

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

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

相关文章

英语单词拼读小程序开发制作介绍

英语单词拼读小程序开发制作介绍本英语单词拼读小程序系统开发的主要功能有&#xff1a; 1、按年级分类展示每个年级阶段的英语单词信息。 2、点击选择的单词进入单词拼读页面&#xff0c;展示英语单词的拼读音标、中文意思、单词发音、拆分词汇发音、用户通过朗读发音对比。通…

华为管理变革之道:管理制度创新

目录 华为崛起两大因素&#xff1a;管理制度创新和组织文化。 管理是科学&#xff0c;150年来管理史上最伟大的创新是流程 为什么要变革&#xff1f; 向世界标杆学习&#xff0c;是变革第一方法论 体系之一&#xff1a;华为的DSTE战略管理体系&#xff08;解决&#xff1a…

基于Spring Boot的中国戏曲文化传播系统

一、系统背景与意义 中国戏曲作为中华民族的文化瑰宝&#xff0c;具有深厚的历史底蕴和艺术价值。然而&#xff0c;随着现代生活节奏的加快和娱乐方式的多样化&#xff0c;传统戏曲文化的传播和普及面临诸多挑战。因此&#xff0c;开发一个基于Spring Boot的中国戏曲文化传播系…

GitLab安装及使用

目录 一、安装 1.创建一个目录用来放rpm包 2.检查防火墙状态 3.安装下载好的rpm包 4.修改配置文件 5.重新加载配置 6.查看版本 7.查看服务器状态 8.重启服务器 9.输网址 二、GitLab的使用 1.创建空白项目 2.配置ssh 首先生成公钥&#xff1a; 查看公钥 把上面的…

14-zookeeper环境搭建

0、环境 java&#xff1a;1.8zookeeper&#xff1a;3.5.6 1、下载 zookeeper下载点击这里。 2、安装 下载完成后解压&#xff0c;放到你想放的目录里。先看一下zookeeper的目录结构&#xff0c;如下图&#xff1a; 进入conf目录&#xff0c;复制zoo_sample.cfg&#xff0…

C++---------动态内存管理

以下是对 C 中相关概念的详细说明及代码示例&#xff1a; 一、动态分配和堆 new 操作符&#xff1a; new 操作符用于在堆上动态分配内存。它会调用对象的构造函数&#xff08;如果是类对象&#xff09;并返回指向分配内存的指针。示例&#xff1a; #include <iostream&g…

R语言数据分析案例46-不同区域教育情况回归分析和探索

一、研究背景 教育是社会发展的基石&#xff0c;对国家和地区的经济、文化以及社会进步起着至关重要的作用。在全球一体化进程加速的今天&#xff0c;不同区域的教育发展水平呈现出多样化的态势。这种差异不仅体现在教育资源的分配上&#xff0c;还表现在教育成果、教育投入与…

单机和微服务的区别,微服务有什么问题?数据一致性问题怎么解决?幂等问题怎么解决?

单机和微服务的区别&#xff0c;微服务有什么问题&#xff1f;数据一致性问题怎么解决&#xff1f;幂等问题怎么解决&#xff1f; 单机架构和微服务架构在设计理念、部署和扩展性上有显著区别。 单机架构 vs 微服务架构 单机架构 定义&#xff1a;所有组件&#xff08;前端…

基于springboot+vue实现的卷烟营销统计分析系统 (源码+L文+ppt)4-129

摘 要 卷烟行业的快速发展使得卷烟营销统计分析系统成为了一个必不可少的工具。基于Java的卷烟营销统计分析系统旨在提供高效、准确和便捷的适用卷烟营销服务。本文讲述了基于java语言开发&#xff0c;后台数据库选择MySQL进行数据的存储。该软件的主要功能是进行卷烟营销统计…

mac启ssh服务用于快速文件传输

x.1 在mac上启SSH服务 方法一&#xff1a;图形交互界面启ssh&#xff08;推荐&#xff09; 通过sharing - advanced - remote login来启动ssh&#xff1b;&#xff08;中文版mac应该是 “系统设置 → 通用 → 共享”里打开“远程登录”来启动&#xff09; 查看自己的用户名和…

青蛇人工智能学家

青蛇人工智能学家 青蛇&#xff0c;是蓝星上&#xff0c;最出名的人工智能学家。 在蓝星上&#xff0c;大家都知道&#xff0c;青蛇人工智能学家&#xff0c;最大的爱好&#xff0c;是美食。 青蛇人工智能学家&#xff0c;对自己的食物&#xff0c;非常在意&#xff0c;对自己的…

[c++进阶(三)]单例模式及特殊类的设计

1.前言 在实际场景中,总会遇见一些特殊情况,比如设计一个类,只能在堆上开辟空间, 或者是设计一个类只能实例化一个对象。那么我们应该如何编写代码呢&#xff1f;本篇将会详细的介绍 本章重点&#xff1a; 本篇文章着重讲解如何设计一些特殊 的类,包括不能被拷贝,只能在栈/堆上…

【LLM论文日更】| 训练大型语言模型在连续潜在空间中进行推理

论文&#xff1a;https://arxiv.org/pdf/2412.06769代码&#xff1a;暂未开源机构 &#xff1a;Meta领域&#xff1a;思维链发表&#xff1a;arxiv 研究背景 研究问题&#xff1a;这篇文章要解决的问题是如何在大语言模型&#xff08;LLMs&#xff09;中实现一种新的推理范式&…

opc da 服务器数据 转 opc ua项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 应用条件 4 查看OPC DA服务器的相关参数 5 配置网关采集opc da数据 6 用opc ua协议转发采集的数据 7 在服务器上运行仰科OPC DA采集软件 8 案例总结 1 案例说明 在OPC DA服务器上运行OPC DA client软件查看OPC DA服务器的相关参…

学习threejs,PerspectiveCamera透视相机和OrthographicCamera正交相机对比

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.PerspectiveCamera透…

PHP后执行php.exe -v命令报错并给出解决方案

文章目录 一、执行php.exe -v命令报错解决方案 一、执行php.exe -v命令报错 -PHP Warning: ‘C:\windows\SYSTEM32\VCRUNTIME140.dll’ 14.38 is not compatible with this PHP build linked with 14.41 in Unknown on line 0 解决方案 当使用PHP8.4.1时遇到VCRUNTIME140.dll…

分布式调度框架学习笔记

一、分布式调度框架的基本设计 二、线程池线程数量设置的基本逻辑 cpu是分时复用的方法&#xff0c;线程是cpu调度的最小单元 如果当前cpu核数是n&#xff0c;计算密集型线程数一般设为n&#xff0c;io密集型(包括磁盘io和网络io)线程数一般设置为2n. 计算密集型线程数一般设…

vue 基础学习

一、ref 和reactive 区别 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><div id"app"><h1>{{Web.title}}</h1><h1&…

CI/CD是什么?

CI/CD 定义 CI/CD 代表持续集成和持续部署&#xff08;或持续交付&#xff09;。它是一套实践和工具&#xff0c;旨在通过自动化构建、测试和部署来改进软件开发流程&#xff0c;使您能够更快、更可靠地交付代码更改。 持续集成 (CI)&#xff1a;在共享存储库中自动构建、测试…

论文阅读:Deep Fusion Clustering Network With Reliable Structure Preservation

论文地址&#xff1a;Deep Fusion Clustering Network With Reliable Structure Preservation | IEEE Journals & Magazine | IEEE Xplore 代码地址&#xff1a;https://github.com/gongleii/DFCN-RSP 摘要 深度聚类通过优雅地利用数据表示来寻找样本的划分&#xff0c;已…