设计模式- 享元模式(Flyweight Pattern)结构|原理|优缺点|场景|示例

                                    设计模式(分类)        设计模式(六大原则)   

    创建型(5种)        工厂方法         抽象工厂模式        单例模式        建造者模式        原型模式

    结构型(7种)        适配器模式        装饰器模式        代理模式        ​​​​​​外观模式      桥接模式        组合模式       享元模式

    行为型(11种)      策略模式        模板方法模式        观察者模式        迭代器模式        责任链模式        命令模式

                                   备忘录模式          状态模式          访问者模式        中介者模式    


享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享已存在的类似对象来有效支持大量细粒度对象的复用,从而降低系统内存占用并提高性能。它适用于对象的大部分状态都可以被外部化,而只有少量内在状态(共享部分)需要存储在享元对象中。这种模式通过共享内部状态相同的对象,避免了大量相似对象的创建。

模式结构

享元模式主要包含以下角色:

  1. Flyweight(抽象享元类)

    • 定义了享元对象的公共接口,通常包括共享状态的访问方法和非共享状态的操作方法。
    • 提供一个或多个工厂方法,用于创建或获取享元对象。
  2. ConcreteFlyweight(具体享元类)

    • 实现抽象享元类的接口,存储享元对象的内部状态(共享部分)。
    • 提供操作内部状态的方法。
  3. UnsharedConcreteFlyweight(非共享具体享元类,可选)

    • 对于某些不适合共享的状态,可以创建非共享的具体享元类来处理。
  4. FlyweightFactory(享元工厂)

    • 负责创建和管理享元对象,确保享元对象的唯一性。
    • 提供一个方法来获取享元对象,如果该对象已存在,则直接返回已创建的享元对象;否则创建一个新的享元对象并返回。
  5. Client(客户端)

    • 通过享元工厂请求享元对象。
    • 向享元对象传递外部状态(非共享部分)。

工作原理

  • 客户端:通过享元工厂请求享元对象,并向对象传递必要的外部状态。
  • FlyweightFactory:根据客户端请求创建或查找已存在的享元对象,并返回给客户端。
  • ConcreteFlyweight:存储并操作内部状态,对外部状态作出响应。

优缺点

优点
  • 减少对象创建数量:通过共享内部状态相同的对象,显著减少了系统中对象的数量,节省内存。
  • 提高性能:由于对象数量减少,对象的创建、销毁和垃圾回收等操作的开销也相应减小。
  • 支持大量细粒度对象:对于需要创建大量相似对象的场景,享元模式能有效应对。
缺点
  • 增加复杂性:引入享元模式后,系统需要管理享元对象的创建、共享和外部状态传递,增加了设计和实现的复杂性。
  • 外部状态管理:客户端需要负责传递外部状态给享元对象,这可能使得客户端代码与享元对象的交互变得复杂。
  • 不适合所有场景:并非所有对象都能被共享。只有当对象的大部分状态可以被外部化时,享元模式才适用。

适用场景

  • 对象数量巨大且内部状态大部分相同:当系统需要处理大量相似对象,且这些对象的大部分状态是共享的,可以考虑使用享元模式。
  • 内存消耗成为瓶颈:当内存资源有限,对象创建和存储的成本较高时,通过享元模式减少对象数量可以改善性能。
  • 对象的创建成本高于使用成本:如果创建一个对象比多次复用该对象更耗时或耗资源,享元模式可以减少创建开销。

代码示例(以Java为例)

// 抽象享元类
interface Character {void display(char symbol, int x, int y);
}// 具体享元类
class CharacterImpl implements Character {private char symbol;public CharacterImpl(char symbol) {this.symbol = symbol;}@Overridepublic void display(char symbol, int x, int y) {System.out.println("Displaying character '" + symbol + "' at (" + x + ", " + y + ")");// 这里假设实际操作是绘制字符到屏幕上,但实际位置由外部状态(x, y)决定}
}// 享元工厂
class CharacterFactory {private Map<Character, CharacterImpl> flyweights = new HashMap<>();public Character getCharacter(char symbol) {if (!flyweights.containsKey(symbol)) {flyweights.put(symbol, new CharacterImpl(symbol));}return flyweights.get(symbol);}
}// 客户端代码
public class FlyweightPatternDemo {public static void main(String[] args) {CharacterFactory factory = new CharacterFactory();Character a = factory.getCharacter('A');Character b = factory.getCharacter('B');a.display('A', 10, 10);b.display('B', 20, 20);// 即使多次请求相同的字符,也不会创建新的对象Character anotherA = factory.getCharacter('A');assert a == anotherA;  // 指向同一享元对象}
}

代码示例(以Python为例)

使用Python实现享元模式的一个示例,我们将创建一个简单的字符渲染系统,其中每个字符都是一个享元对象,它们的内部状态是字符本身,而外部状态则是渲染时的位置(x, y坐标):

from typing import Dict, Tuple
import weakrefclass Character:"""抽象享元类"""def __init__(self, symbol: str):self._symbol = symboldef display(self, position: Tuple[int, int]):"""显示字符,外部状态由客户端传递"""print(f"Displaying character '{self._symbol}' at {position}")class CharacterFactory:"""享元工厂类"""_flyweights: Dict[str, weakref.ReferenceType[Character]] = {}@classmethoddef get_character(cls, symbol: str) -> Character:"""获取或创建字符享元对象。如果字符享元已经存在,则直接返回;否则创建新的享元对象并添加到缓存中。"""flyweight_ref = cls._flyweights.get(symbol)if flyweight_ref is not None and flyweight_ref() is not None:return flyweight_ref()flyweight = Character(symbol)cls._flyweights[symbol] = weakref.ref(flyweight)return flyweightdef main():factory = CharacterFactory()# 请求并显示两个不同的字符a = factory.get_character('A')a.display((10, 10))b = factory.get_character('B')b.display((20, 20))# 再次请求相同的字符,应当返回已存在的享元对象another_a = factory.get_character('A')assert a is another_aprint("Characters displayed using the Flyweight pattern.")if __name__ == "__main__":main()

在这个Python示例中:

  • Character类作为抽象享元类,定义了享元对象的公共接口(display方法),并存储了字符的内部状态(字符符号)。
  • CharacterFactory类作为享元工厂,使用一个字典来缓存已创建的享元对象。字典的键是字符符号,值是弱引用(weakref)以避免循环引用导致内存泄漏。当客户端请求某个字符时,如果该字符的享元对象已存在,则直接返回;否则创建一个新的享元对象,添加到字典中,并返回该对象的弱引用。
  • main函数展示了客户端如何使用享元工厂来获取字符享元对象,并通过display方法传递外部状态(显示位置)。当请求相同的字符时,工厂会返回同一个享元对象,证明了享元模式的有效性。

运行此代码,将会看到字符在指定位置被正确显示,且两次请求相同的字符时,返回的是同一个对象实例。这就是享元模式在Python中的应用。

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

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

相关文章

PHP 爬虫如何配置代理 IP(CURL 函数)

在 PHP中 配置代理IP&#xff0c;可以通过设置 CURL 库的选项来实现&#xff0c;代码如下&#xff1a; 当然你要有代理ip来源&#xff0c;比如我用的这个 代理商 &#xff0c;如果想服务稳定不建议找开源代理池&#xff0c;避免被劫持。 <?php // 初始化cURL会话 $ch cu…

php序列化存储和反序列化的使用方法

在 PHP 中,序列化(serialization)是将一个变量转换为可存储或传输的字符串表示形式的过程。反序列化(unserialization)则是将这个字符串转换回原始的 PHP 变量。这在存储对象到数据库、缓存系统或者在网络中传输对象时非常有用。 序列化 PHP 提供了 serialize() 函数来序…

xgp会员一年多少钱?xgp一个月多少钱?微软商店xgp会员价格指南

xgp是xbox游戏平台。xgp是类似于steam、epic等&#xff0c;拥有丰富游戏资源的平台。该平 台的全称为“XBox Game Pass”&#xff0c;俗称为“西瓜皮”。xgp是会员订阅模式&#xff0c;开启会员后&#xff0c;所有游戏资源都为你开放。pc版的&#xff0c;第一个月10港币&#x…

基于springboot+vue+Mysql的漫画网站

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

前端分页请求数据,前端删除n条数据后,再次请求

期望实现 前端分页请求服务端数据&#xff0c;页面渲染成列表前端操作删除列表里一项或多项&#xff08;一条或多条数据&#xff09;&#xff0c;页面立刻移除这一项或多项前端再次分页请求服务端数据&#xff0c;列表正常显示 问题分析 一般来说&#xff0c;每次请求的数据…

L1-099 帮助色盲 - java

L1-099 帮助色盲 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB 题目描述&#xff1a; 在古老的红绿灯面前&#xff0c;红绿色盲患者无法分辨当前亮起的灯是红色还是绿色&#xff0c;有些聪明人通过路口的策略是这样的&#xff1a;当红灯或绿灯亮起时&am…

WebServer项目介绍文章【四叶专属】

Linux项目实战C轻量级Web服务器源码分析TinyWebServer 书接上文&#xff0c;学习开源项目的笔记没想到居然有不少阅读量&#xff0c;后面结合另一个前端开源项目简单做了点修改&#xff0c;没想到居然有需要的同学&#xff0c;那么我就专门为四叶开一篇文章吧&#xff0c;【源码…

抢先看!美团、京东、360等大厂面试题解析,技术面试必备。

技术面试必备&#xff01;美团、京东、360等大厂面试题详解&#xff0c;让你轻松应对各大公司面试挑战&#xff01; 往期硬核面经 哦耶&#xff01;冲进腾讯了&#xff01; 牛逼&#xff01;上岸腾讯互娱和腾讯TEG&#xff01; 腾讯的面试&#xff0c;强度拉满&#xff01; …

【c++】探究C++中的list:精彩的接口与仿真实现解密

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章来到list有关部分&#xff0c;这一部分函数与前面的类似&#xff0c;我们简单讲解&#xff0c;重难点在模拟实现时的迭代器有关实现 目录 1.List介绍2.接…

【网络安全】跨站脚本攻击(XSS)

专栏文章索引&#xff1a;网络安全 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、XSS简介 二、XSS漏洞危害 三、XSS漏洞类型 1.反射型XSS 2.存储型XSS 3.DOM型XSS 四、XSS漏洞防御 一、XSS简介 XSS&#xff08;Cross-Site Scripting&#xff09; XSS 被…

信奥之路(三)——判断语句if

1.if语句 判断结构要求程序员指定一个或多个要评估或测试的条件&#xff0c;以及条件为真时要执行的语句&#xff08;必需的&#xff09;和条件为假时要执行的语句。 C 编程语言提供了以下类型的判断语句。点击链接查看每个语句的细节&#xff1a; if 语句&#xff1a;一个 if …

设计模式(019)行为型之状态模式

状态模式是一种行为型设计模式&#xff0c;它允许对象在内部状态发生变化时改变它的行为&#xff0c;使得对象在不同状态下有不同的行为表现&#xff0c;而且可以方便地添加新的状态而不必修改已有的代码。 1、场景设计 实现场景&#xff1a;对状态A和状态B做出不同的处理。 …

Git merge的版本冲突实验

实验目的 发现 两个分支的 相同文件 怎样被修改 才会发生冲突&#xff1f; 实验过程 1.初始状态 现在目前有1.py、2.py两个文件&#xff0c;已经被git管理。现在我想制造冲突&#xff0c;看怎样的修改会发生冲突&#xff0c;先看怎么不会发生冲突。 目前仓库里的版本是这样…

C++ //练习 13.11 为前面练习中的HasPtr类添加一个析构函数。

C Primer&#xff08;第5版&#xff09; 练习 13.11 练习 13.11 为前面练习中的HasPtr类添加一个析构函数。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 class HasPtr{ public:HasPtr(const std::string &s std::stri…

C语言实现简单CRC校验

目录 一、实现题目 二、send模块 三、receive模块 四、运行截图 一、实现题目 二、send模块 #include <stdio.h> #include <string.h>// 执行模2除法&#xff0c;并计算出余数&#xff08;CRC校验码&#xff09; //dividend被除, divisor除数 void divide…

免费SSL证书和付费SSL证书区别在哪

免费SSL证书与付费SSL证书在多个方面存在差异&#xff0c;这些差异主要体现在认证级别、保障金额以及服务范围上。在以下几个方面存在显著区别&#xff1a; 1、验证类型和信任级别&#xff1a; 免费SSL证书&#xff1a;通常只提供域名验证&#xff08;DV&#xff09;级别的证…

实验:使用apache + yum实现自制yum仓库

实验准备 Web服务器端&#xff1a;cenos-1&#xff08;IP&#xff1a;10.9.25.33&#xff09; 客户端&#xff1a;centos-2 保证两台机器网络畅通&#xff0c;原yum仓库可用&#xff0c;关闭防火墙和selinux Web服务器端 ①安装httpd并运行&#xff0c;设置开机自启动 安装…

微信小程序 带tab的页面 从数据比较多的tab切到数据比较少的tab时 有可能触发onReachBottom 导致数据重复加载

onReachBottom() {//添加pageNum 1的判断是因为 从tab页比较高的地方切到tab页子集很少的地方可能会直接触发onReachBottom导致数据重复加载if (pageNum 1) return..doing},

多模态模型

转换器成功作为构建语言模型的一种方法&#xff0c;促使 AI 研究人员考虑同样的方法是否对图像数据也有效。 研究结果是开发多模态模型&#xff0c;其中模型使用大量带有描述文字的图像进行训练&#xff0c;没有固定的标签。 图像编码器基于像素值从图像中提取特征&#xff0c;…

力扣数据库题库学习(4.23日)

610. 判断三角形 问题链接 解题思路 题目要求&#xff1a;对每三个线段报告它们是否可以形成一个三角形。以 任意顺序 返回结果表。 对于三个线段能否组成三角形的判定&#xff1a;任意两边之和大于第三边&#xff0c;对于这个表内的记录&#xff0c;要求就是&#xff08;x…