首页 > 系统相关 >享元模式及其运用场景:结合工厂模式和单例模式优化内存使用

享元模式及其运用场景:结合工厂模式和单例模式优化内存使用

时间:2024-11-05 13:50:04浏览次数:4  
标签:享元 状态 color 模式 对象 单例 共享

介绍

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享对象来减少内存使用,尤其是对于大量相似对象的场景。享元模式通常与工厂模式单例模式结合使用,从而有效地控制和复用对象的创建。在享元模式中,享元对象的核心思想是将不可变的部分(共享的状态)和可变的部分(外部状态)进行区分,从而优化系统性能。

工厂模式与单例模式

享元模式与工厂模式紧密结合,享元工厂负责管理共享的享元对象。工厂模式使得创建和管理享元对象变得统一和高效。除此之外,单例模式也常用于确保享元工厂在整个系统中唯一,避免重复创建享元工厂实例,从而节省资源。

下面代码采用静态内部类的方式实现单例模式,这种方式不仅能保证线程安全,还能确保只有在首次使用时才创建实例,具有懒加载特性。但是枚举才是最优的单例模式实现。感兴趣的同学可以参考这篇文章单例模式最优解----枚举

享元模式的结构

享元模式的核心结构包含以下几个角色:

  1. 抽象享元角色(Flyweight):这是一个接口或抽象类,声明了享元对象的公共方法。享元对象可以通过这些方法向外界提供共享的数据,同时也可以设置外部数据。

  2. 具体享元角色(Concrete Flyweight):实现了抽象享元接口,提供了共享的内部状态。在享元工厂中,这些具体享元对象可以通过共享池来复用。

  3. 非共享的具体享元角色(Unshared Flyweight):这些对象不适合共享,通常包含外部状态。每次使用时都会直接实例化。

  4. 享元工厂角色(Flyweight Factory):负责管理和提供享元对象。享元工厂会检查是否已经有符合要求的享元对象,如果没有则创建新的对象并返回。

享元模式中的共享与非共享状态

享元模式中有两种主要状态:

  • 内部状态:这些状态是享元对象的一部分,并且是共享的。内部状态不会随着环境的改变而改变。

  • 外部状态:这些状态是依赖于外部环境的,通常随时间、位置等变化。外部状态不会存储在享元对象中,而是通过方法传递给享元对象。

享元模式的关键在于将这两种状态进行分离,只有内部状态才能被共享,外部状态则由客户端负责传递。

示例:图形编辑器中的享元模式

在这里插入图片描述

在这个例子中,我们设计了一个简单的图形编辑器,其中有两种共享形状:圆形和正方形。每个图形的颜色作为内部状态共享,而位置作为外部状态传递。通过享元模式,我们可以复用相同颜色的图形对象,并为每个图形传递不同的位置。如果没有采用共享的方式,每次调用图形时都会创建新的对象,这样会导致大量内存浪费。但位置不能复用,这是根据外部环境改变的。

代码实现

// 抽象享元角色
interface Shape {
    void draw(String externalState);
}

// 具体享元类 - 圆形,内部状态是共享的
class Circle implements Shape {
    private String color;  // 内部状态,颜色是共享的

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

    @Override
    public void draw(String externalState) {
        System.out.println("Drawing Circle with color: " + color + " at position: " + externalState);
    }
}

// 具体享元类 - 正方形,内部状态是共享的
class Square implements Shape {
    private String color;  // 内部状态,颜色是共享的

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

    @Override
    public void draw(String externalState) {
        System.out.println("Drawing Square with color: " + color + " at position: " + externalState);
    }
}

// 非共享的具体享元 - 线条,完全依赖外部状态
class Line implements Shape {
    @Override
    public void draw(String externalState) {
        System.out.println("Drawing Line at position: " + externalState);
    }
}

// 享元工厂
class ShapeFactory {
    private Map<String, Shape> shapeMap = new HashMap<>();

    private ShapeFactory() {}  // 私有构造函数,防止外部创建实例

    // 静态内部类实现单例模式
    private static class SingletonHelper {
        private static final ShapeFactory INSTANCE = new ShapeFactory();
    }

    // 获取单例实例
    public static ShapeFactory getInstance() {
        return SingletonHelper.INSTANCE;
    }

    // 获取共享的享元对象
    public Shape getShape(String type, String color) {
        String key = type + color;
        if (!shapeMap.containsKey(key)) {
            if (type.equals("Circle")) {
                shapeMap.put(key, new Circle(color));
            } else if (type.equals("Square")) {
                shapeMap.put(key, new Square(color));
            }
        }
        return shapeMap.get(key);
    }
}


public class FlyweightPatternExample {
    public static void main(String[] args) {
        // 享元工厂
        ShapeFactory shapeFactory = ShapeFactory.getInstance();

        // 创建和使用共享的享元对象
        Shape circle1 = shapeFactory.getShape("Circle", "Red");
        Shape circle2 = shapeFactory.getShape("Circle", "Red");
        Shape square1 = shapeFactory.getShape("Square", "Blue");

        // 绘制图形时,外部状态(位置)会变化
        circle1.draw("10, 20");  // 外部状态为位置
        circle2.draw("15, 25");
        square1.draw("30, 40");

        // 非共享的享元对象(直接实例化)
        Shape line = new Line();
        line.draw("50, 60");  // 外部状态为位置
    }
}

代码说明

  1. 共享的具体享元类

    • CircleSquare 是共享的享元对象,它们的颜色是内部状态。享元工厂会根据颜色来共享这些对象。
  2. 非共享的具体享元类

    • Line 类是非共享的享元类,它不存储任何内部状态,而是每次都需要通过外部状态(位置)来绘制。它没有参与享元工厂的共享池。
  3. 享元工厂

    • ShapeFactory 类负责管理和返回共享的享元对象。它使用一个 Map 来缓存已创建的享元对象,避免重复创建相同的对象。
  4. 客户端使用

    • 客户端首先通过享元工厂请求共享的图形对象(如红色圆形)。如果该对象已存在,则直接返回;否则,创建一个新的对象。
    • 对于非共享的对象(如线条),客户端直接实例化,而不通过享元工厂。

总结

享元模式通过共享对象的方式有效减少了内存使用,尤其适用于对象数量庞大且状态相似的场景。JDK中也有享元模式的应用,感兴趣的同学可以往这看---->JDK享元模式的运用

标签:享元,状态,color,模式,对象,单例,共享
From: https://blog.csdn.net/weixin_54574094/article/details/143503672

相关文章

  • 《图解设计模式》 第九部分 避免浪费
    第二十章Flyweight模式publicclassBigcharFactory{//这里对使用到的内容进行了缓存privateHashMappool=newHashMap();//有则直接取,无则创建并保存到缓存。publicsynchronizedBigChargetBigChar(charcharname){BigCharbc=(BigChar)pool.get("......
  • 《图解设计模式》 第八部分 管理状态
    第17章Observer模式publicabstractclassNumberGenerator{privateArrayListobserverList=newArrayList();/*部分代码省略*///加入基础类,当需要通知的时候通知publicvoidaddObserver(Observerobserver){observerList.add(observer);}pub......
  • 装饰者模式
    目录装饰者模式的概念装饰者模式的主要结构1.基础饮品类(Tea):2.具体饮品类(OriginalMilkTea):3.装饰者基类(TeaDecorator):4.具体装饰者(PearlDecorator和CreamDecorator):5.主函数:总结装饰者模式的概念    装饰者模式是指在不改变原有对象的基础上,将功能附加在对......
  • 常见设计模式-工厂模式
    文章目录1.简单工厂模式2.工厂方法模式3.抽象工厂模式设计模式七大原则工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但由子类决定要实例化的类是哪一个。工厂模式让一个类的实例化延迟到其子类。工厂模式主要分为三种:简单工厂模式、工厂方法模式......
  • 《图解设计模式》 第七部分 简单化
    Facade模式publicclassMain{publicstaticvoidmain(String[]args){PageMaker.makeWelcomePage("[email protected]","welcom.html");}}publicclassPageMaker{publicstaticvoidmakeWelcompage(Stringmailaddr,Stringfile......
  • 《图解设计模式》 第五部分 访问数据结构
    第十三章Visotor模式publicclassfileextendsentry{/*省略*/puhblicvoidaccept(Visitorv){v.visit(this);}}publicclassMain{publicstaticvoidmain(Stringargs){Directoryrootdir=newDirctory("root");/*省略*/ro......
  • AI赛道盈利模式揭秘——以AIStarter为例【AI数字人、大模型、工作流...】
    随着人工智能技术的飞速发展,越来越多的企业涌入这一赛道,试图在激烈的市场竞争中占据一席之地。作为其中的一员,AIStarter凭借其独特的商业模式和技术创新,成功地在市场上站稳了脚跟。本文将深入探讨AIStarter的盈利模式,揭示其成功的秘密。AIStarter概述AIStarter是一家专注于提......
  • 从零开始学AIStarter:创作者模式全攻略【AI工作流、数字人、大模型、对话、设计...】
    在数字化时代,项目管理工具成为了提高工作效率、促进团队协作不可或缺的一部分。对于创作者来说,选择一个既能满足个性化需求又能提供高效管理支持的平台尤为重要。AIStarter项目管理平台正是这样一款专为创意人士设计的强大工具,它不仅提供了丰富的功能来帮助用户更好地组织工作......
  • 《图解设计模式》 第五部分 一致性
    第11章Composite模式文中举例文件夹系统,简单说明:这里可以讲File和dirctory看作一种东西Entry。在Entry的基础上分化两者,构成结构。能够使容器与内容具有一致性,创造出递归结构。第12章Decorator模式publicclassMain{publicstaticvoidmain(String[]ar......