掌握设计模式--享元模式

享元模式(Flyweight Pattern)

享元模式是一种结构型设计模式,它通过共享相同的对象来减少内存使用,从而提升性能。它适用于有大量相似对象的场景,通过共享相同的对象来避免创建大量重复对象。强调的是共享对象,不共享对象的行为。

核心思想

将对象分为 内部状态(Intrinsic State)外部状态(Extrinsic State)

  • 内部状态:可以被共享,不会随环境变化而改变。
  • 外部状态:依赖于具体的场景,不可共享,需要通过客户端传递给享元对象。

这样说可能太抽象了,看文中的代码示例具体的感受下。

组成部分

  1. Flyweight(享元接口)

    定义共享对象的接口,描述公共行为。

  2. ConcreteFlyweight(具体享元类)

    实现共享对象的具体行为,保存内部状态。

  3. UnsharedConcreteFlyweight(非共享享元类)

    不需要共享的对象,通常包含具体的子节点组合。

  4. FlyweightFactory(享元工厂)

    管理享元对象的创建和共享,确保合理地创建和复用对象。

  5. Client(客户端)

    负责传递外部状态给享元对象。

案例实现

围棋示例,棋子共享对象下棋的位置非共享对象,通过享元工厂控制棋子的创建,整个棋盘中只有黑白两种棋子,一共只会创建两个对象,变化的只是下棋的位置,而下棋的位置由客户端决定

案例类图

代码实现

java 复制代码
import java.util.HashMap;
import java.util.Map;

// 享元接口:棋子
interface Flyweight {
    void display(String position); // 外部状态:棋子的位置
}

// 具体享元类:棋子的颜色可以共享
class GoPieceFlyweight implements Flyweight {
    private final String color; // 棋子的颜色(黑或白)

    public GoPieceFlyweight(String color) {
        this.color = color;
    }

    @Override
    public void display(String position) {
        System.out.println("Go Piece: Color = " + color + ", Position = " + position);
    }
}

// 享元工厂:负责管理享元对象的创建和共享
class GoPieceFactory {
    private static final Map<String, Flyweight> flyweightMap = new HashMap<>();

    // 同一种颜色的棋子只会创建一次
    public static Flyweight getFlyweight(String color) {
        // 如果已有该颜色的棋子,直接返回;否则创建新的棋子
        if (!flyweightMap.containsKey(color)) {
            flyweightMap.put(color, new GoPieceFlyweight(color));
            System.out.println("创建新围棋棋子,颜色为: " + color);
        }
        return flyweightMap.get(color);
    }
}

// 下棋操作
class PlayChess{

    public void play(String color, String position){
        // 享元工厂创建享元对象:共享棋子颜色(黑或白)
        Flyweight piece = GoPieceFactory.getFlyweight(color);
        // 外部状态:棋子的位置
        piece.display(position);
    }
}

// 客户端代码:围棋棋盘
public class GoGame {
    public static void main(String[] args) {
        // 围棋开局
        PlayChess playChess = new PlayChess();
        // 白棋先手
        playChess.play("White","D4");
        playChess.play("Black","D5");
        playChess.play("White","C6");
        playChess.play("Black","D9");
        System.out.println("--------------------------------------");
        // 围棋开局:其它用户也开局
        PlayChess playChess2 = new PlayChess();
        // 黑棋先手
        playChess2.play("Black","D7");
        playChess2.play("White","E8");
        playChess2.play("Black","D9");
        playChess2.play("White","D5");

    }
}

测试结果简析

测试输出结果

创建新围棋棋子,颜色为: White

Go Piece: Color = White, Position = D4

创建新围棋棋子,颜色为: Black

Go Piece: Color = Black, Position = D5

Go Piece: Color = White, Position = C6

Go Piece: Color = Black, Position = D9


Go Piece: Color = Black, Position = D7

Go Piece: Color = White, Position = E8

Go Piece: Color = Black, Position = D9

Go Piece: Color = White, Position = D5

结果简析

整个代码执行过程只创建两个棋子对象,变化的只有位置信息。逐一分析如下

  1. 共享的内部状态

棋子的 颜色 (黑色或白色)是共享的,棋盘上的每个棋子不需要重新创建相同颜色的棋子实例。工厂方法 getFlyweight() 保证对于相同颜色的棋子,始终使用相同的对象。

例如,无论在棋盘的任何位置放置黑棋,都会复用相同的黑色棋子实例。

  1. 独立的外部状态

每个棋子的 位置 (如 D4、C6 等)是外部状态,它随棋局变化而变化,因此不共享,客户端在调用 display() 方法时传递具体位置。

  1. 享元工厂

享元工厂 GoPieceFactory 负责管理不同颜色棋子的创建和共享。当请求相同颜色的棋子时,工厂返回已存在的实例;否则创建一个新的实例。

  1. 复用共享对象

在后续的棋步中,如果再次放置黑色棋子,GoPieceFactory 会复用之前创建的黑色棋子对象,而不需要重新创建。

优缺点和适用场景

优点

  1. 节省内存:通过共享对象,避免了大量重复对象的内存占用。
  2. 性能优化:减少了对象创建的开销。

缺点

  1. 引入了复杂性:需要分离内部和外部状态,并通过工厂管理对象的共享。
  2. 不适用于外部状态过于复杂的场景。

适用场景

  1. 各种游戏场景、图形绘制等;
  2. 系统中存在大量相似对象,造成内存使用量过高;
  3. 对象的内部状态相对稳定,可以共享。

例如:

  • 文本编辑器中的字符共享;
  • 图形绘制中的共享对象(如游戏中的子弹对象);
  • 数据库连接池。

单例模式与享元模式对比

单例模式

单例模式确保全局只有一个对象实例,它仅需一次内存分配。

享元模式

享元模式通过复用大量相似对象的内部状态,减少内存消耗。在享元模式中,尽管有多个享元对象,但共享的部分(内部状态)是复用的,外部状态通常由客户端提供,从而减少内存占用。

总结

享元模式强调的是共享对象,不共享对象的行为。通过共享对象来优化内存使用,尤其适用于有大量相似对象的场景。它通过分离对象的内部状态和外部状态,实现了内部状态的内存复用,减少了对象创建的开销。在需要管理大量细粒度对象的应用中,享元模式是一个非常有效的解决方案。

需要查看往期设计模式文章的,可以在个人主页中或者文章开头的集合中查看,可关注我,持续更新中。。。


超实用的SpringAOP实战之日志记录

2023年下半年软考考试重磅消息

通过软考后却领取不到实体证书?

计算机算法设计与分析(第5版)

Java全栈学习路线、学习资源和面试题一条龙

软考证书=职称证书?

软考中级--软件设计师毫无保留的备考分享

相关推荐
silver6872 小时前
状态模式详解
设计模式
JINGWHALE12 小时前
设计模式 行为型 状态模式(State Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·状态模式
游客5204 小时前
设计模式-结构型-桥接模式
开发语言·python·设计模式·桥接模式
苹果6 小时前
C++二十三种设计模式之工厂方法模式
c++·设计模式·工厂方法模式
程序研6 小时前
工厂方法模式
java·设计模式
全栈若城7 小时前
4种革新性AI Agent工作流设计模式全解析
人工智能·设计模式
迪迦不喝可乐15 小时前
软考 高级 架构师 第十一章 面向对象分析 设计模式
java·设计模式
苹果16 小时前
C++二十三种设计模式之迭代器模式
c++·设计模式·迭代器模式
silver68716 小时前
迭代器模式详解
设计模式