【设计模式】【结构型模式(Structural Patterns)】之享元模式(Flyweight Pattern)

1. 设计模式原理说明

享元模式(Flyweight Pattern) 是一种用于性能优化的设计模式,其主要目的是通过共享尽可能多的对象来有效地支持大量的细粒度的对象。在享元模式中,细粒度的对象被称为“享元”,这些对象可以被共享,以减少内存的使用并提高效率。享元模式特别适用于那些对象数量巨大且大部分状态可以外部化的情况。

主要角色
  1. Flyweight(享元):定义一个接口,通过这个接口,Flyweight 可以接受并作用于外部状态。
  2. ConcreteFlyweight(具体享元):实现 Flyweight 接口,并为内部状态增加存储空间。一个 ConcreteFlyweight 对象必须是可共享的。通常情况下,它会被多个对象所共享。
  3. UnsharedConcreteFlyweight(不可共享的具体享元):并不是所有的 Flyweight 子类都需要被共享,因此 Flyweight 接口中声明的方法对于不可共享的具体享元同样适用。
  4. FlyweightFactory(享元工厂):负责创建和管理 Flyweight 对象。确保合理地共享 Flyweight 对象,当用户请求一个 Flyweight 对象时,FlyweightFactory 提供一个已有的实例或者创建一个新的实例。

2. UML 类图及解释

UML 类图
+-------------------+                +-----------------------+
|   Flyweight       |<--(implements)| ConcreteFlyweight     |
|-------------------|                |-----------------------|
| + operation(extrinsicState: String): void | + operation(extrinsicState: String): void |
+-------------------+                +-----------------------+^|
+-----------------------+              |
| UnsharedConcreteFlyweight |          |
|-----------------------|             |
| + operation(extrinsicState: String): void | +-----------------------+
+-----------------------+                | FlyweightFactory         |+-----------------------+| + getFlyweight(key: String): Flyweight |+-----------------------+
类图解释
  • Flyweight:定义了一个接口,通过这个接口,享元可以接收并作用于外部状态。
  • ConcreteFlyweight:实现了 Flyweight 接口,包含内部状态,可以被多个对象共享。
  • UnsharedConcreteFlyweight:虽然实现了 Flyweight 接口,但它的对象不能被共享,每个实例都有自己的状态。
  • FlyweightFactory:负责创建和管理享元对象。它使用一个数据结构(如哈希表)来存储已经创建的享元对象,以便复用。

3. 代码案例及逻辑详解

Java 代码案例
// 享元接口
interface Flyweight {void operation(String extrinsicState);
}// 具体享元
class ConcreteFlyweight implements Flyweight {private final String intrinsicState;public ConcreteFlyweight(String intrinsicState) {this.intrinsicState = intrinsicState;}@Overridepublic void operation(String extrinsicState) {System.out.println("Intrinsic State = " + this.intrinsicState);System.out.println("Extrinsic State = " + extrinsicState);}
}// 不可共享的具体享元
class UnsharedConcreteFlyweight implements Flyweight {@Overridepublic void operation(String extrinsicState) {System.out.println("I am not shared.");}
}// 享元工厂
class FlyweightFactory {private Map<String, Flyweight> flyweights = new HashMap<>();public Flyweight getFlyweight(String key) {if (!flyweights.containsKey(key)) {flyweights.put(key, new ConcreteFlyweight(key));}return flyweights.get(key);}
}// 客户端
public class Client {public static void main(String[] args) {FlyweightFactory factory = new FlyweightFactory();Flyweight fly1 = factory.getFlyweight("Key1");fly1.operation("Extrinsic State 1");Flyweight fly2 = factory.getFlyweight("Key1");fly2.operation("Extrinsic State 2");Flyweight unshared = new UnsharedConcreteFlyweight();unshared.operation("Extrinsic State 3");}
}
C++ 代码案例
#include <iostream>
#include <map>
#include <memory>
#include <string>// 享元接口
class Flyweight {
public:virtual void operation(const std::string& extrinsicState) const = 0;virtual ~Flyweight() {}
};// 具体享元
class ConcreteFlyweight : public Flyweight {
private:std::string intrinsicState;
public:ConcreteFlyweight(const std::string& state) : intrinsicState(state) {}void operation(const std::string& extrinsicState) const override {std::cout << "Intrinsic State = " << intrinsicState << std::endl;std::cout << "Extrinsic State = " << extrinsicState << std::endl;}
};// 不可共享的具体享元
class UnsharedConcreteFlyweight : public Flyweight {
public:void operation(const std::string& extrinsicState) const override {std::cout << "I am not shared." << std::endl;}
};// 享元工厂
class FlyweightFactory {
private:std::map<std::string, std::shared_ptr<Flyweight>> flyweights;
public:std::shared_ptr<Flyweight> getFlyweight(const std::string& key) {if (flyweights.find(key) == flyweights.end()) {flyweights[key] = std::make_shared<ConcreteFlyweight>(key);}return flyweights[key];}
};// 客户端
int main() {FlyweightFactory factory;auto fly1 = factory.getFlyweight("Key1");fly1->operation("Extrinsic State 1");auto fly2 = factory.getFlyweight("Key1");fly2->operation("Extrinsic State 2");UnsharedConcreteFlyweight unshared;unshared.operation("Extrinsic State 3");return 0;
}
Python 代码案例
from abc import ABC, abstractmethod
from collections import defaultdict# 享元接口
class Flyweight(ABC):@abstractmethoddef operation(self, extrinsic_state: str) -> None:pass# 具体享元
class ConcreteFlyweight(Flyweight):def __init__(self, intrinsic_state: str) -> None:self._intrinsic_state = intrinsic_statedef operation(self, extrinsic_state: str) -> None:print(f"Intrinsic State = {self._intrinsic_state}")print(f"Extrinsic State = {extrinsic_state}")# 不可共享的具体享元
class UnsharedConcreteFlyweight(Flyweight):def operation(self, extrinsic_state: str) -> None:print("I am not shared.")# 享元工厂
class FlyweightFactory:_flyweights: dict[str, Flyweight] = {}def get_flyweight(self, key: str) -> Flyweight:if key not in self._flyweights:self._flyweights[key] = ConcreteFlyweight(key)return self._flyweights[key]# 客户端
if __name__ == "__main__":factory = FlyweightFactory()fly1 = factory.get_flyweight("Key1")fly1.operation("Extrinsic State 1")fly2 = factory.get_flyweight("Key1")fly2.operation("Extrinsic State 2")unshared = UnsharedConcreteFlyweight()unshared.operation("Extrinsic State 3")
Go 代码案例
package mainimport ("fmt"
)// 享元接口
type Flyweight interface {operation(extrinsicState string)
}// 具体享元
type ConcreteFlyweight struct {intrinsicState string
}func (f *ConcreteFlyweight) operation(extrinsicState string) {fmt.Printf("Intrinsic State = %s\n", f.intrinsicState)fmt.Printf("Extrinsic State = %s\n", extrinsicState)
}// 不可共享的具体享元
type UnsharedConcreteFlyweight struct{}func (u *UnsharedConcreteFlyweight) operation(extrinsicState string) {fmt.Println("I am not shared.")
}// 享元工厂
type FlyweightFactory struct {flyweights map[string]Flyweight
}func NewFlyweightFactory() *FlyweightFactory {return &FlyweightFactory{flyweights: make(map[string]Flyweight)}
}func (f *FlyweightFactory) getFlyweight(key string) Flyweight {if fw, ok := f.flyweights[key]; ok {return fw}fw := &ConcreteFlyweight{intrinsicState: key}f.flyweights[key] = fwreturn fw
}// 客户端
func main() {factory := NewFlyweightFactory()fly1 := factory.getFlyweight("Key1")fly1.operation("Extrinsic State 1")fly2 := factory.getFlyweight("Key1")fly2.operation("Extrinsic State 2")unshared := &UnsharedConcreteFlyweight{}unshared.operation("Extrinsic State 3")
}

4. 总结

享元模式 是一种用于性能优化的设计模式,通过共享尽可能多的对象来有效支持大量细粒度的对象。这种模式特别适用于那些对象数量巨大且大部分状态可以外部化的情况。

主要优点
  1. 减少了内存的使用:通过共享对象,减少了内存的占用,特别是在对象数量庞大的情况下。
  2. 提高了性能:减少了对象的创建和销毁,提高了应用程序的性能。
  3. 支持大规模的应用程序:适合于需要处理大量对象的应用程序,如图形界面、文档编辑器等。
主要缺点
  1. 增加了系统的复杂性:为了管理和共享对象,系统会变得更加复杂。
  2. 内部状态和外部状态的分离:需要明确区分哪些状态是内部的,哪些是外部的,这可能会增加开发的难度。
适用场景
  • 当一个应用程序使用了大量的对象,而这些对象的部分状态可以外部化时。
  • 当需要使用大量的相似对象,而这些对象的大多数状态都可以外部化时。
  • 当对象的大部分状态都可以转换成外部状态时,使用享元模式可以显著减少内存的占用。

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

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

相关文章

redis命令 及 redis 常见的数据结构

文章目录 一. 核心命令1. set2. get 二. 全局命令1. keys2. exists3. del4. expire5. ttl6. type 三. redis 常见的数据结构 一. 核心命令 1. set set key value key 和 value 都是string类型的 对于key value, 不需要加上引号, 就是表示字符串类型, 加上也可以 redis中, 不…

跨平台应用开发框架(4)----Qt(系统篇)

目录 1.Qt事件 1.事件来源 2.事件处理 3.按键事件 1.组合按键 4.鼠标事件 1.鼠标单击事件 2.鼠标释放事件 3.鼠标双击事件 4.鼠标移动事件 5.滚轮事件 5.定时器 1.QTimerEvent类 2.QTimer 类 3.获取系统日期及时间 6.事件分发器 7.事件过滤器 2.Qt文件 1.输入…

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…

DM达梦管理工具拖出空白区块,无法关闭

1. 出现问题&#xff1a;DM达梦管理工具拖出空白区块&#xff0c;无法关闭。 2. 解决方法 新建查询页&#xff0c;把查询页拖到空白区块里&#xff0c;完全覆盖空白区块。之后空白区块会变成查询页&#xff0c;右上角会出现叉号&#xff0c;点击叉号关闭就行。 3. 后记 达梦…

DevExpress的web Dashboard应用

本文旨在从零开始创建一个包含dashboard的应用 一、前期准备 1、语言&#xff1a;C# 2、软件&#xff1a;Visual Studio 2019 3、框架&#xff1a;DevExpress19.2(付费)、ASP.NET(Web) 4、组件&#xff1a;dashboard 二、创建ASP.NET Web窗体仪表板应用程序 1、创建一个空的w…

【vue-router】Vue-router如何实现路由懒加载

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

go语言切片

切片 切片是一种数据结构&#xff0c;这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的&#xff0c;可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的…

2024年一级建造师考试成绩,即将公布!

一级建造师考试成绩一般在考试结束后3个月左右的时间公布&#xff01; 根据官方通知&#xff0c;重庆、江苏、青海、江西、云南、湖南、福建、北京、山西、黑龙江等地在今年一建报名通知里提到&#xff1a;2024年一级建造师考试成绩预计于2024年12月上旬公布。考生可在这个时间…

基于Matlab的图像去噪算法仿真

中值滤波的仿真 本节选用中值滤波法对含有高斯噪声和椒盐噪声的图像进行去噪&#xff0c;并用Matlab软件仿真。 &#xff08;1&#xff09;给图像加入均值为0&#xff0c;方差为0.02的高斯噪声&#xff0c;分别选择33模板、55模板和77模板进行去噪 Matlab部分代码&#xff1…

交通流量预测:基于交通流量数据建立模型

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

嵌入式QT学习第4天:Qt 信号与槽

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本章思维导图如下&#xff1a; 不使用 Qt Designer 的方式进行开发&#xff0c;用代码绘界面&#xff0c;可以锻炼我们的布局能力&#xff0c;和代码逻辑能力&#x…

多线程+线程池

普通线程的创建 三种创建方式实例&#xff1a; 多线程本质上是毫无关系的&#xff0c;执行顺序是不可预知的&#xff0c;但是由于callable方式创建的对象有返回值所以主函数在执行的时候&#xff0c;需要等待返回值回来才能继续执行其他线程&#xff0c;所以在这种状态下是…

mac访达打开终端

选择文件夹打开 选中文件夹&#xff0c;然后右键即可&#xff1a; 在当前文件夹打开 在访达的当前文件夹长按option键 左下角出现当前文件夹路径 右键即可打开终端

【模型剪枝】YOLOv8 模型剪枝实战 | 稀疏化-剪枝-微调

文章目录 0. 前言1. 模型剪枝概念2. 模型剪枝实操2.1 稀疏化训练2.2 模型剪枝2.3 模型微调总结0. 前言 无奈之下,我还是写了【模型剪枝】教程🤦‍♂️。回想当年,在写《YOLOv5/v7进阶实战专栏》 时,我经历了许多挫折,才最终完成了【模型剪枝】和【模型蒸馏】的内容。当时…

Django 路由层

1. 路由基础概念 URLconf (URL 配置)&#xff1a;Django 的路由系统是基于 urls.py 文件定义的。路径匹配&#xff1a;通过模式匹配 URL&#xff0c;并将请求传递给对应的视图处理函数。命名路由&#xff1a;每个路由可以定义一个名称&#xff0c;用于反向解析。 2. 基本路由配…

单点登录原理

允许跨域–>单点登录。 例如https://www.jd.com/ 同一个浏览器下&#xff1a;通过登录页面产生的cookie里的一个随机字符串的标识&#xff0c;在其他子域名下访问共享cookie获取标识进行单点登录&#xff0c;如果没有该标识则返回登录页进行登录。 在hosts文件下面做的域名…

保持角色一致性!flux新模型redux用法(含模型与工作流)

​ 目录 redux模型是什么&#xff0c;能干啥&#xff1f; 用到的工具有哪些&#xff1f; 工具和模型文件在哪里下载&#xff1f; 整合包&#xff1a; 下载后需要分别放到指定目录&#xff1a; redux模型怎么用&#xff1f; 加载工作流 上传图片和输入提示词 生成结果…

FastAPI 跨域访问cors设置

问题发现 前端vue3写了个页面&#xff0c;调用后台一个服务&#xff0c;出现了跨域访问错误&#xff0c;截图如下&#xff1a; 示例代码如下&#xff1a; from typing import Unionfrom fastapi import FastAPI from pydantic import BaseModel import randomapp FastAPI()…

Admin.NET框架使用宝塔面板部署步骤

文章目录 Admin.NET框架使用宝塔面板部署步骤&#x1f381;框架介绍部署步骤1.Centos7 部署宝塔面板2.部署Admin.NET后端3.部署前端Web4.访问前端页面 Admin.NET框架使用宝塔面板部署步骤 &#x1f381;框架介绍 Admin.NET 是基于 .NET6 (Furion/SqlSugar) 实现的通用权限开发…

音视频流媒体直播/点播系统EasyDSS互联网视频云平台介绍

随着互联网技术的飞速发展&#xff0c;音视频流媒体直播已成为现代社会信息传递与娱乐消费的重要组成部分。在这样的背景下&#xff0c;EasyDSS互联网视频云平台应运而生&#xff0c;它以高效、稳定、便捷的特性&#xff0c;为音视频流媒体直播领域带来了全新的解决方案。 1、产…