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

享元模式(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全栈学习路线、学习资源和面试题一条龙

软考证书=职称证书?

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

相关推荐
huangyujun99201232 小时前
设计模式杂谈-模板设计模式
java·设计模式
magic 2452 小时前
Java设计模式:责任链模式
java·设计模式·责任链模式
YGGP13 小时前
【结构型模式】代理模式
设计模式
庄小焱18 小时前
设计模式——中介者设计模式(行为型)
设计模式
庄小焱20 小时前
设计模式——备忘录设计模式(行为型)
设计模式
庄小焱20 小时前
设计模式——代理设计模式(结构型)
设计模式
哆啦A梦的口袋呀21 小时前
基于Python学习《Head First设计模式》第三章 装饰者模式
python·学习·设计模式
哆啦A梦的口袋呀21 小时前
基于Python学习《Head First设计模式》第五章 单件模式
python·学习·设计模式
季鸢1 天前
Java设计模式之备忘录模式详解
java·设计模式·备忘录模式
摘星编程1 天前
工厂方法模式深度解析:从原理到应用实战
java·设计模式·软件工程·工厂方法模式