设计模式之 享元模式

news/2024/11/22 13:24:18/

享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少系统中对象的数量,从而节省内存和提升性能。它通过共享相同的对象来避免重复创建类似的对象。该模式尤其适用于对象数量庞大、且重复内容较多的场景。

核心思想:将对象的状态划分为内蕴状态(Intrinsic State)和外蕴状态(Extrinsic State),内蕴状态是可以共享的部分,而外蕴状态则由客户端管理并在需要时动态传递。

一、享元模式的特点

  1. 状态拆分

    • 内蕴状态:对象中可以共享的不变部分,由享元对象内部存储。
    • 外蕴状态:对象中可变的部分,不存储在享元对象中,由客户端动态提供。
  2. 对象共享

    系统只会为每种内蕴状态创建一个享元对象,并在不同上下文中重复使用这些对象。
  3. 性能优化

    通过共享对象,减少内存开销,提升系统性能。

二、享元模式的结构

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

  1. 抽象享元(Flyweight)

    定义享元对象的公共接口,外部通过该接口与具体享元对象交互。
  2. 具体享元(ConcreteFlyweight)

    实现抽象享元接口,并存储内蕴状态。具体享元对象需要支持可以共享的功能。
  3. 非共享具体享元(UnsharedConcreteFlyweight)

    并非所有的享元对象都需要共享,这些对象不能被多个客户端共享,但也实现了享元接口。
  4. 享元工厂(FlyweightFactory)

    管理享元对象的创建和共享,确保客户端获取的享元对象是唯一的,避免重复创建。
  5. 客户端(Client)

    负责维护外蕴状态,并与享元对象交互。

三、享元模式的工作原理

  1. 客户端通过享元工厂获取享元对象。
  2. 如果享元对象已存在,工厂返回共享对象;如果不存在,则工厂创建新的享元对象。
  3. 客户端将外蕴状态传递给享元对象,享元对象结合其内蕴状态执行操作。

四、享元模式的实现

下面通过一个实例展示享元模式的实现。

示例:棋盘上的棋子

在一个棋盘游戏中,棋子的位置是变化的(外蕴状态),而棋子的颜色(黑/白)是固定的(内蕴状态)。我们可以使用享元模式来优化棋子的管理。

  • 抽象享元类
    public interface ChessPiece {void display(int x, int y);
    }
  • 具体享元类
    public class ConcreteChessPiece implements ChessPiece{private String color;public ConcreteChessPiece(String color){this.color = color;}@Overridepublic void display(int x,int y) {System.out.println("棋子颜色" + color + ",棋子位置:(" + x + "," + y + ")" );}
    }
  • 享元工厂
    public class ChessPieceFactory {private static Map<String,ChessPiece> map = new HashMap<>();public static ChessPiece getChessPiece(String color) {if (!map.containsKey(color)) {map.put(color, new ConcreteChessPiece(color));}return map.get(color);}
    }
    
  • 客户端
    public class Client {public static void main(String[] args) {// 获取共享的棋子ChessPiece black1 = ChessPieceFactory.getChessPiece("黑色");ChessPiece black2 = ChessPieceFactory.getChessPiece("黑色");ChessPiece white1 = ChessPieceFactory.getChessPiece("白色");// 设置外蕴状态(棋子的位置)black1.display(1, 1);black2.display(2, 3);white1.display(4, 5);// 验证共享对象System.out.println("黑色棋子是否相同: " + (black1 == black2));}
    }
  • 运行结果

五、享元模式的优缺点

优点:
  1. 减少内存占用

    通过共享对象,避免了重复的对象实例,大幅度降低系统的内存开销。
  2. 提升性能

    减少对象创建的次数和垃圾回收的频率,提升系统性能。
  3. 适用于大量小对象

    享元模式尤其适合那些数量多、内容重复的对象。
缺点:
  1. 实现复杂

    需要对对象的状态进行拆分,并精心设计共享机制,增加了系统的复杂度。
  2. 不适用所有场景

    如果共享对象的数量过少,或者内蕴状态和外蕴状态之间的界限不清晰,享元模式的优势难以体现。
  3. 增加了客户端的职责

    客户端需要管理外蕴状态,这可能导致客户端代码的复杂度提高。

六、享元模式的应用场景

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

  1. 大量相似对象

    系统中存在大量内容重复的对象,且这些对象的部分状态是可以共享的。
  2. 内存优化需求强

    内存占用是系统性能的瓶颈,迫切需要通过共享对象来节省内存。
  3. 不变性场景

    对象的共享部分是不可变的,这样才能安全地在不同上下文中共享。
常见案例:
  • 文本处理:在文本编辑器中,每个字符的字体、颜色等属性可以共享,具体的位置由外部管理。
  • 图形界面:在绘图程序中,重复的图形对象(如线条、圆形)可以共享。
  • 游戏开发:在大型游戏中,地图上的树木、建筑等对象可以共享。
  • 数据库连接池:共享连接对象,避免重复创建连接。

七、享元模式的拓展

  1. 非共享享元

    并非所有对象都适合共享。如果某些对象需要独占使用,则可以通过非共享享元类实现。
  2. 复合享元模式

    组合模式和享元模式结合使用,可以将享元对象组成一个树形结构,从而支持更复杂的共享场景。
  3. 线程安全性

    享元对象通常是不可变的,这样可以在多线程环境中安全共享。

http://www.ppmy.cn/news/1549043.html

相关文章

基于 RBF 神经网络整定的 PID 控制

基于 RBF 神经网络整定的 PID 控制 是结合了传统 PID 控制和 RBF&#xff08;径向基函数&#xff09;神经网络的自适应控制方法。在这种方法中&#xff0c;RBF 神经网络用于自适应地调整 PID 控制器的增益&#xff08;比例增益 KpK_pKp​&#xff0c;积分增益 KiK_iKi​ 和微分…

Vue实战案例:一步步构建企业级项目1

一、Vue程序的概述 Vue是一个能用于构建用户界面的渐进式框架框架&#xff0c;主要用于开发单页应用程序&#xff08;SPA&#xff09;和动态用户界面。‌ Vue由尤雨溪&#xff08;Evan You&#xff09;在2014年创建&#xff0c;是前端三大主流框架之一&#xff0c;其他两个是A…

ROSSERIAL与Arduino IDE交叉开发(UBUNTU环境,包含ESP32、arduino nano)

ROSSERIAL与Arduino IDE交叉开发 一、简介二、安装1、Ubuntu下的Arduino IDE安装 **针对ESP32报错问题原因溯源和修改**三、运行结点 一、简介 这个教程展示在ubuntu环境下如何利用Arduino IDE配合rosserial开发机器人部件。通过Arduino IDErosserial实现arduino/esp32开发板通…

系统思考—结构影响行为

过去的成功&#xff0c;是实力&#xff0c;还是“电梯效应”&#xff1f; 在经济高速发展的那些年&#xff0c;就像站在一部一直上升的电梯里&#xff0c;数字不断跳动&#xff0c;仿佛一切尽在掌握。但当电梯停下&#xff0c;你继续沿用过去的方法&#xff0c;甚至更拼、更卷…

PW系列工控电脑复制机:效率与精度双重提升

工控电脑复制应用&#xff1a;效率与精度的双重提升 随着现代企业对大数据、数据备份、和跨平台兼容性需求的快速增长&#xff0c;工控电脑已成为数据密集型产业的核心设备。针对工控环境中大量数据复制的特殊需求&#xff0c;PW系列NVMe/SATA PCIe SSD复制机&#xff08;如PW…

NuGet如何支持HTTP源

今天是2024年11月21号&#xff0c;最近更新了VisualStudio后发现HTTP的包源已经默认禁止使用了&#xff0c;生成时会直接报错。如下图&#xff1a; 官方也明确指出了要想使用HTTP包源的解决办法&#xff0c;这里就简单总结一下。 一、全局配置 1、全局NuGet包的配置文件路径在…

富格林:安全指正规防欺诈套路

富格林指出&#xff0c;在现货黄金投资操作中&#xff0c;有众多的投资技巧和投资方式&#xff0c;但其实并不是所有的都适用。投资者应该注意选择安全、可信的投资方式去规防欺诈套路。值得提醒的是&#xff0c;现货黄金虽然拥有很多获利的机会&#xff0c;但也有不少欺诈套路…

DAY3 多进程并发通讯

服务器代码&#xff1a; #include <myhead.h> #define IP "192.168.128.59" #define PORT 8888 #define BACKLOG 20 void fun(int sss) {if(sssSIGCHLD){while(waitpid(-1,NULL,0)>0);} } int main(int argc, const char *argv[]) {if(signal(SIGCHLD,fun)…