DukeDuke
主页
项目文档
技术文档
  • 单机版
  • 微服务
  • 代办项目
  • 优鲜项目
项目管理
关于我们
主页
项目文档
技术文档
  • 单机版
  • 微服务
  • 代办项目
  • 优鲜项目
项目管理
关于我们
  • 技术文档

    • 网络原理

      • 交换机
      • 路由器
      • TCP/IP协议
      • HTTP 与 HTTPS
    • 软件架构

      • 什么是软件架构
      • 分层架构
      • 微服务架构
      • 事件驱动架构
      • 领域驱动设计(DDD)
      • 架构图
      • 高并发系统
    • Vue3

      • Vue3简介
      • Vue3响应式系统
      • Vue3组合式API
      • Vue3生命周期
      • Vue3模板语法
      • Vue3组件系统
      • Vue3 路由系统
      • Vue3 状态管理
      • Vue3 性能优化
      • Vue3 TypeScript 支持
      • Vue3 项目实战
      • VUE 面试题大全
      • Node.js 安装
    • JAVA

      • JVM

        • 认识JVM
        • JVM类加载器
        • 运行时数据区
        • 执行引擎
        • 本地方法接口
        • 本地方法库
        • JVM垃圾回收
        • JVM性能监控
        • JVM调优
      • 设计模式
        • 单例模式
        • 工厂模式
        • 策略模式
        • 适配器模式
        • 建造者模式
        • 原型模式
        • 装饰器模式
        • 代理模式
        • 外观模式
        • 享元模式
        • 组合模式
        • 桥接模式
      • Java多线程

        • Java 线程基础详解
        • Java 线程池详解
        • Java ThreadLocal 详解
        • Java volatile 详解
        • Java 线程间通信详解
        • Java 线程安全详解
        • Java 线程调度详解
        • Java 线程优先级详解

        • Java 线程中断详解
        • Java 线程死锁详解
      • Java反射
      • Java 面试题

        • Java 基础概念面试题
        • Java 面向对象编程面试题
        • Java 集合框架面试题
        • Java 多线程与并发面试题
        • JVM 与内存管理面试题
        • Java I/O 与 NIO 面试题
        • Java 异常处理面试题
        • Java 反射与注解面试题
        • Java Spring 框架面试题
        • Java 数据库与 JDBC 面试题
        • Java 性能优化面试题
        • Java 实际项目经验面试题
        • Java 高级特性面试题
        • Java 面试准备建议
    • Python

      • Python简介
      • Python安装
      • Python hello world
      • Python基础语法
      • Python数据类型
      • Python数字
      • Python字符串
      • Python列表
      • Python元组
      • Python字典
      • Python日期时间
      • Python文件操作
      • Python异常处理
      • Python函数
      • Python类
      • Python模块
      • Python包
      • Python多线程
      • Python面向对象
      • Python爬虫
      • Django web框架
      • Python 面试题

        • Python 面试题导航
        • Python 基础概念
        • Python 面向对象编程
        • Python 数据结构
        • Python 高级特性
        • Python 框架
        • Python 性能优化
        • Python 项目经验
    • Spring

      • Spring
      • Springboot
      • Spring Security 安全框架
      • SpringBoot 中的事件详解
      • SpringBoot 中的定时任务详解
      • SpringBoot 自动装配原理与源码解释
    • Mybatis

      • Mybatis
      • Mybatis-Plus
    • 数据库

      • Redis

        • Redis简介
        • Redis(单机)安装
        • Redis配置
        • Redis数据结构
        • RDB、AOF 和混合持久化机制
        • Redis内存管理
        • Redis缓存一致性
        • Redis缓存穿透
        • Redis缓存击穿
        • Redis缓存雪崩
        • Redis Lua脚本
        • Redis主从复制
        • Redis哨兵模式
        • Redis集群
        • Redis数据分片
        • Redis CPU使用率过高
        • Redis面试题
      • MySQL

        • MySQL简介
        • MySQL安装
        • MySQL配置
        • MYSQL日常维护
        • MYSQL优化-慢查询
        • MYSQL优化-索引
        • MYSQL数据库设计规范
    • 消息队列

      • RocketMQ
      • Kafka
      • RabbitMQ
      • 消息队列面试题
    • 微服务

      • SpringCloud 微服务
      • Eureka 注册中心
      • Nacos 注册中心
      • Gateway 网关
      • Feign 服务调用
      • Sentinel 限流 与 熔断
      • Seata 分布式事务
      • CAP 理论
      • Redis 分布式锁
      • 高并发系统设计
    • ELK日志分析系统

      • Elasticsearch 搜索引擎
      • Logstash 数据处理
      • Kibana 可视化
      • ELK 实战
    • 开放API

      • 开放API设计
      • 开放API示例项目
    • 人工智能

      • 人工智能简介
      • 机器学习

      • 深度学习

      • 自然语言处理

      • 计算机视觉

        • CUDA与cuDNN详细安装
        • Conda 安装
        • Pytorch 深度学习框架
        • yolo 目标检测
        • TensorRT 深度学习推理优化引擎
        • TensorFlow 机器学习
        • CVAT 图像标注
        • Windows 下安装 CUDA、cuDNN、TensorRT、TensorRT-YOLO 环境
        • Windows10+CUDA+cuDNN+TensorRT+TensorRT-YOLO 部署高性能YOLO11推理
    • 大数据

      • 大数据简介
      • Hadoop 数据存储
      • Flume 数据采集
      • Sqoop 数据导入导出
      • Hive 数据仓库
      • Spark 数据处理
      • Flink 数据处理
      • Kafka 数据采集
      • HBase 数据存储
      • Elasticsearch 搜索引擎
    • 图像处理

      • 图像处理简介
      • 医学图像web呈现
      • 医学图像处理
      • 切片细胞分离问题
    • 服务器&运维

      • Linux 系统

        • Linux 系统管理
        • Linux 网络管理
        • Linux 文件管理
        • Linux 命令大全
      • Nginx Web 服务器

        • Nginx 安装 与 配置
        • Nginx 负载均衡
        • Nginx SSL证书配置
        • Nginx Keepalived 高可用
      • Docker 容器

        • Docker 简介
        • Docker 安装与配置
        • Docker 命令
        • Docker 部署 Nginx
        • Docker 部署 MySQL
        • Docker 部署 Redis
      • 服务器

        • 塔式服务器
        • 机架式服务器
        • 刀片服务器
      • Git 版本控制
      • Jenkins 持续集成
      • Jmeter 性能测试
      • Let's Encrypt 免费SSL证书
    • 简历

      • 项目经理简历
      • 开发工程师简历

享元模式

概述

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术有效地支持大量细粒度对象的复用。享元模式通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似对象的开销,从而提高系统资源的利用率。

定义

享元模式:运用共享技术有效地支持大量细粒度对象的复用。

核心思想

  • 共享:将对象的公共部分提取出来,多个对象共享这些公共部分
  • 细粒度:对象被设计为细粒度的,可以共享
  • 不可变:享元对象的状态是不可变的,避免并发问题

结构

角色定义

  1. Flyweight(抽象享元类):定义对象的内部状态和外部状态的接口或实现
  2. ConcreteFlyweight(具体享元类):实现抽象享元类定义的接口
  3. UnsharedConcreteFlyweight(非共享具体享元类):不能被共享的子类
  4. FlyweightFactory(享元工厂类):创建并管理享元对象,确保合理地共享享元对象
  5. Client(客户端):维持一个对享元的引用,计算或存储享元的外部状态

类图

┌─────────────────┐    creates    ┌─────────────────────┐
│ FlyweightFactory│ ────────────► │   ConcreteFlyweight │
└─────────────────┘               └─────────────────────┘
         │                                  ▲
         │ uses                             │
         ▼                                  │
┌─────────────────┐               ┌─────────────────────┐
│     Client      │ ─────────────► │   AbstractFlyweight │
└─────────────────┘               └─────────────────────┘

实现示例

示例 1:文字编辑器中的字符对象

// 抽象享元类
public abstract class Character {
    protected char symbol;
    protected int size;
    protected String font;

    public abstract void display(int x, int y);
}

// 具体享元类
public class ConcreteCharacter extends Character {
    public ConcreteCharacter(char symbol, int size, String font) {
        this.symbol = symbol;
        this.size = size;
        this.font = font;
    }

    @Override
    public void display(int x, int y) {
        System.out.println("显示字符 '" + symbol + "' 在位置 (" + x + "," + y +
                          ") 使用字体 " + font + " 大小 " + size);
    }
}

// 享元工厂类
public class CharacterFactory {
    private Map<String, Character> characterPool = new HashMap<>();

    public Character getCharacter(char symbol, int size, String font) {
        String key = symbol + "_" + size + "_" + font;

        if (!characterPool.containsKey(key)) {
            characterPool.put(key, new ConcreteCharacter(symbol, size, font));
            System.out.println("创建新字符对象: " + key);
        } else {
            System.out.println("复用已存在的字符对象: " + key);
        }

        return characterPool.get(key);
    }

    public int getPoolSize() {
        return characterPool.size();
    }
}

// 客户端
public class TextEditor {
    private CharacterFactory factory = new CharacterFactory();
    private List<Character> characters = new ArrayList<>();

    public void addCharacter(char symbol, int size, String font, int x, int y) {
        Character character = factory.getCharacter(symbol, size, font);
        characters.add(character);
        character.display(x, y);
    }

    public void showPoolInfo() {
        System.out.println("字符池大小: " + factory.getPoolSize());
    }
}

示例 2:围棋棋子

// 抽象享元类
public abstract class ChessPiece {
    protected String color;

    public abstract void place(int x, int y);
}

// 具体享元类
public class BlackChessPiece extends ChessPiece {
    public BlackChessPiece() {
        this.color = "黑色";
    }

    @Override
    public void place(int x, int y) {
        System.out.println(color + "棋子放置在位置 (" + x + "," + y + ")");
    }
}

public class WhiteChessPiece extends ChessPiece {
    public WhiteChessPiece() {
        this.color = "白色";
    }

    @Override
    public void place(int x, int y) {
        System.out.println(color + "棋子放置在位置 (" + x + "," + y + ")");
    }
}

// 享元工厂类
public class ChessPieceFactory {
    private Map<String, ChessPiece> piecePool = new HashMap<>();

    public ChessPiece getChessPiece(String color) {
        if (!piecePool.containsKey(color)) {
            if ("黑色".equals(color)) {
                piecePool.put(color, new BlackChessPiece());
            } else if ("白色".equals(color)) {
                piecePool.put(color, new WhiteChessPiece());
            }
            System.out.println("创建新的" + color + "棋子");
        } else {
            System.out.println("复用已存在的" + color + "棋子");
        }

        return piecePool.get(color);
    }
}

// 客户端
public class GoGame {
    private ChessPieceFactory factory = new ChessPieceFactory();

    public void placePiece(String color, int x, int y) {
        ChessPiece piece = factory.getChessPiece(color);
        piece.place(x, y);
    }
}

使用场景

  1. 大量相似对象:系统中存在大量相似对象,需要缓冲池的场景
  2. 内存敏感:需要节省内存,提高性能的场景
  3. 对象状态分离:对象的大部分状态可以外部化,且可以将这些外部状态传入对象中
  4. 缓存:需要缓存大量对象的场景

典型应用

  • 文字编辑器中的字符对象
  • 图形编辑器中的图形对象
  • 游戏中的棋子、子弹等对象
  • 数据库连接池
  • 线程池

优缺点

优点

  1. 内存效率:大幅减少内存使用,特别是当有大量相似对象时
  2. 性能提升:减少对象创建和销毁的开销
  3. 资源共享:通过共享机制提高资源利用率
  4. 扩展性好:易于扩展新的享元类型

缺点

  1. 复杂性增加:增加了系统的复杂性
  2. 状态管理:需要仔细管理内部状态和外部状态
  3. 线程安全:享元对象通常是不可变的,需要考虑线程安全问题
  4. 调试困难:共享对象可能导致调试困难

注意事项

  1. 状态分离:正确区分内部状态和外部状态
  2. 不可变性:享元对象应该是不可变的
  3. 工厂管理:使用工厂类管理享元对象的创建和获取
  4. 内存监控:注意监控享元池的大小,避免内存泄漏

与其他模式的关系

  • 单例模式:享元工厂通常使用单例模式实现
  • 组合模式:享元模式可以与组合模式结合使用
  • 策略模式:享元对象可以包含策略对象

总结

享元模式是一种重要的结构型设计模式,特别适用于需要处理大量相似对象的场景。通过共享机制,它可以显著提高系统的性能和内存效率。在实际应用中,需要根据具体场景合理使用,并注意状态管理和线程安全等问题。

最近更新:: 2025/8/14 09:20
Contributors: Duke
Prev
外观模式
Next
组合模式