首页 > 其他分享 >享元模式

享元模式

时间:2024-09-17 15:02:39浏览次数:10  
标签:享元 状态 对象 模式 color 棋子 共享

享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享大量细粒度对象来减少内存使用。它在需要创建大量相似对象的场景中尤其有用,通过共享对象来降低内存开销,从而提高性能。

核心思想

享元模式将对象的状态分为两部分:

  1. 内部状态(Intrinsic State):不随外部环境改变,可以共享的状态。它通常是对象的一部分,用来定义该对象的属性。例如,在象棋游戏中,棋子的颜色就是内部状态,它在不同的棋子对象中是相同的,可以共享。
  2. 外部状态(Extrinsic State):随外部环境变化的状态,不能被共享。它通常是对象的具体表现属性,例如象棋棋子的位置就是外部状态,不同的棋子有不同的位置,不能共享。

结构组成

享元模式通常由以下几个部分组成:

  1. Flyweight(享元接口):定义对象的公共接口,外部状态的操作通常由该接口来完成。
  2. ConcreteFlyweight(具体享元类):实现享元接口,并且存储可以共享的内部状态。
  3. UnsharedConcreteFlyweight(非共享具体享元类):并非所有对象都需要被共享,非共享的对象可以作为享元模式的扩展部分。
  4. FlyweightFactory(享元工厂类):管理享元对象的创建和复用。它确保每个享元对象是唯一的,并管理共享对象的生命周期。

使用场景

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

  1. 有大量相似对象时:如果一个应用程序需要创建大量相似的对象,并且内存消耗成为瓶颈,享元模式可以通过共享对象来减少内存开销。
  2. 对象的多数状态是可以共享的:当对象的状态可以分为内部状态和外部状态,并且内部状态是可以共享的,享元模式能有效降低内存消耗。

优点

  • 减少对象创建,降低内存消耗:通过共享对象,显著减少了内存的占用,提升了系统性能。
  • 提高性能:由于减少了对象的数量,系统运行速度也可能因此得到提升。

缺点

  • 增加系统复杂度:为了实现对象的共享,需要对对象的内部状态和外部状态进行区分,这增加了代码的复杂性。
  • 不适用于所有场景:如果对象的内部状态和外部状态划分不清晰,或者对象数量并不多,享元模式的使用可能得不偿失。

示例

在象棋程序中,享元模式可以用于管理棋子对象:

  • 内部状态:棋子的颜色(黑色或白色)是不变的,可共享的。
  • 外部状态:棋子的位置(坐标)是可变的,不同的棋子有不同的位置,因此不能共享。

通过享元工厂类,创建和管理这些棋子对象,保证相同颜色的棋子是共享的。

享元接口(ChessPiece):

  • 在代码中,ChessPiece 是享元接口,定义了棋子的核心操作——放置棋子(place(int x, int y))。这个接口的作用是为不同的棋子定义一个统一的行为,即放置棋子的位置,而位置是棋子的外部状态,不会在不同对象之间共享。

  • // 享元接口,定义了操作方法
    public interface ChessPiece {
        void place(int x, int y); // 位置是外部状态
    }
    

具体享元类(ConcreteChessPiece):

  • ConcreteChessPiece 是享元模式中的具体享元类,它实现了 ChessPiece 接口。这个类的实例表示象棋中的一个棋子。

  • 内部状态(Intrinsic State): 棋子的颜色 (color) 是内部状态,这部分状态是不可变的,并且在多个相同颜色的棋子对象之间共享。

  • 外部状态(Extrinsic State): 棋子的位置(x, y 坐标)是外部状态,不同棋子的具体位置是通过 place 方法传入的,而不是存储在对象内部,这样多个棋子可以共享相同的颜色对象,但位置各自独立。

    // 具体享元类,实现了享元接口,包含共享的内部状态
    class ConcreteChessPiece implements ChessPiece {
        private final String color; // 颜色是内部状态,不变且可共享
    
        public ConcreteChessPiece(String color) {
            this.color = color;
        }
    
        @Override
        public void place(int x, int y) {
            System.out.println("Placing " + color + " chess piece at (" + x + ", " + y + ")");
        }
    }
    

享元工厂类(ChessPieceFactory):

  • 工厂类 ChessPieceFactory 负责管理和创建享元对象。在享元模式中,工厂类的职责是确保共享对象的合理使用。它通过 getChessPiece(String color) 方法来获取某种颜色的棋子。

  • 如果请求的棋子颜色已经存在(即缓存中已经有该颜色的棋子对象),那么直接返回这个共享对象;如果不存在,则创建一个新的棋子对象并将其缓存起来。

    // 享元工厂类,负责管理和创建享元对象
    class ChessPieceFactory {
        private final Map<String, ChessPiece> pieceMap = new HashMap<>();
    
        public ChessPiece getChessPiece(String color) {
            ChessPiece piece = pieceMap.get(color);
    
            // 如果不存在该颜色的棋子,则创建并放入缓存
            if (piece == null) {
                piece = new ConcreteChessPiece(color);
                pieceMap.put(color, piece);
            }
            return piece;
        }
    }
    
    

客户端(TestFlyweightPattern):

  • 客户端代码展示了如何使用享元模式来创建和使用棋子对象。在 main 方法中,使用 ChessPieceFactory 创建了多个棋子对象,但由于使用了享元模式,相同颜色的棋子实际上是共享同一个对象。

  • 通过 System.out.println(white1 == white2);System.out.println(black1 == black2); 可以验证同一颜色的棋子确实是同一个对象。

    public class TestFlyweightPattern {
        public static void main(String[] args) {
            ChessPieceFactory factory = new ChessPieceFactory();
    
            // 创建并共享白色棋子
            ChessPiece white1 = factory.getChessPiece("White");
            white1.place(1, 1);
    
            ChessPiece white2 = factory.getChessPiece("White");
            white2.place(2, 2);
    
            // 创建并共享黑色棋子
            ChessPiece black1 = factory.getChessPiece("Black");
            black1.place(3, 3);
    
            ChessPiece black2 = factory.getChessPiece("Black");
            black2.place(4, 4);
    
            // 验证共享的对象
            System.out.println(white1 == white2); // true,表明共享了白色棋子对象
            System.out.println(black1 == black2); // true,表明共享了黑色棋子对象
        }
    }
    

总结

享元模式是一种优化内存使用的模式,通过共享对象来减少重复对象的创建,从而提升系统性能。它适用于需要创建大量相似对象的场景,如图形编辑器、文字处理器、游戏开发等。在设计过程中,需要权衡对象共享带来的好处和系统复杂性之间的关系。

标签:享元,状态,对象,模式,color,棋子,共享
From: https://www.cnblogs.com/20lxj666/p/18388823

相关文章

  • 外观模式
    外观模式外观模式(FacadePattern)是一种结构型设计模式,旨在为复杂的子系统提供一个简单的接口。它的核心思想是将系统的复杂性封装在一个统一的接口中,使得外部代码可以通过这个接口简化对复杂系统的操作。主要组成部分外观类(FacadeClass):提供一个简化的接口来访问复杂的子系统......
  • 装饰者模式
    装饰者模式装饰者模式(DecoratorPattern)是一种结构型设计模式,主要用于动态地给对象添加额外的功能,而不改变其结构。这个模式通过创建一个装饰类来包装原始对象,从而扩展其功能。主要角色组件(Component):定义一个接口或抽象类,声明可以被装饰的对象所共有的接口。具体组件(Concrete......
  • 组合模式
    组合模式组合模式(CompositePattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次关系。它允许客户端以统一的方式处理单个对象和对象集合,使得客户端不需要区分具体的对象类型,从而简化了代码的处理逻辑。主要组成部分Component(组件):定义了叶子对象和......
  • 桥接模式
    桥接模式桥接模式(BridgePattern)是一种结构型设计模式,它通过将抽象部分与实现部分分离,从而使它们可以独立地变化。这个模式的主要目的是解耦抽象和实现,使得它们可以独立地变化和扩展。主要概念抽象(Abstraction):这是一个接口或抽象类,它定义了高层次的操作。修正抽象(RefinedA......
  • 【加密算法基础——AES CBC模式代码解密实践】
    AES解密实践之代码实现AES解密使用python脚本比较灵活,但是一定要保证脚本是调试过的,才能在找到正确的密文,密钥,初始向量的情况下,解出正确的明文。但是对于AES解密,命令行无法处理key截断的问题。实际测试了一下,CBC模式,对于key截断的问题可以解决,但是CFB模式,目前还无法实验......
  • 设计模式---- 门面模式
    门面模式门面模式(FacadePattern)是一种结构型设计模式,用于为复杂子系统提供一个统一、简单的接口,隐藏系统的复杂性。通过门面模式,客户端无需直接与系统的内部组件交互,而是通过门面类与系统打交道,简化了客户端的使用,降低了系统的复杂性和耦合度。门面模式的主要概念定义:门面模......
  • 攻防世界 ————新手模式适合作为桌面 misc
    (本篇文章参考大佬的解题)下载附件,得到rar的的压缩包,解压缩,打开文件后有一张图片:打开图片发现什么也没有:使用软件Stegsolve打开图片看有什么问题:点击下一页:点击后发现有一个二维码:把他保存下来,使用软件扫码看看里面有什么:(我是用微信扫码的)出现了十六进制的数字:把他复......
  • 设计模式---- 工厂模式
    工厂模式工厂模式是一种创建型设计模式,它的主要目的是将对象的创建过程与对象的使用过程分离。工厂模式通过引入工厂类或者工厂方法,隐藏对象创建的复杂性,使得代码更加灵活、可扩展。工厂模式的使用场景主要在于:当我们需要对创建的对象进行封装或延迟创建时,工厂模式是一个很好的选......
  • 反DDD模式之关系型数据库
    本文书接上回《图穷匕见-所有反DDD模式都是垃圾》,关注公众号(老肖想当外语大佬)获取信息:最新文章更新;DDD框架源码(.NET、Java双平台);加群畅聊,建模分析、技术实现交流;视频和直播在B站。背景我在与开发者交流关于DDD的建模思路时,往往会遇到一个难题,就是不少经验丰富的开发者,总是带着技......
  • 反DDD模式之关系型数据库
    本文书接上回《图穷匕见-所有反DDD模式都是垃圾》,关注公众号(老肖想当外语大佬)获取信息:最新文章更新;DDD框架源码(.NET、Java双平台);加群畅聊,建模分析、技术实现交流;视频和直播在B站。背景我在与开发者交流关于DDD的建模思路时,往往会遇到一个难题,就是不少经验丰富的开发者,总是带......