【设计模式】享元模式


在这里插入图片描述

主页传送门:💁 传送

1.享元模式定义

       享元模式(Flyweight Pattern)是池技术的重要实现方式,是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。其定义如下:

Use sharing to support large numbers of fine-grained objects efficiently.

       即:使用共享对象可有效地支持大量的细粒度的对象。
       其通用类图如下:
在这里插入图片描述

2.享元模式的角色

享元模式所涉及到的角色有:

  • 抽象享元类(Flyweight):
       它是所有具体享元类的超类。为这些类规定出需要实现的公共接口,那些需要外蕴状态(Exte)的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。

  • 具体享元类(Concrete Flyweight):
       具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。

  • 不能共享的具体享元类(Unsharable Flyweight):
       不能共享的享元类,又叫做复合享元类。一个复合享元对象是由多个单享元对象组成,这些组成的对象是可以共享的,但是复合享元类本身并不能共享。

  • 享元工厂类(Flyweight Factoiy):
       享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。

3.享元模式实战案例

3.1.场景说明

       本次采用图书馆借书的案例来理解享元模式,形式很简单,首先定义一个抽象类,里面有个抽象方法,接着定义子类来继承抽象类,并实现其方法。为了模拟外部状态,还需定义一个用户实体类。构建工厂来作为池存放对象,并暴露获取对象的方法。最后通过调用方法。

3.2.结构类图

       使用享元模式来实现的结构图如下所示::
在这里插入图片描述

3.3.代码实现

抽象类的定义
只有一个借书的方法

package com.lyd.demo.flyweight;
import com.lyd.demo.entity.User;

public abstract class Library {
    public abstract void borrow(User user); // 抽象方法 - 借书
}

抽象类的子类
实现抽象方法

package com.lyd.demo.flyweight;
import com.lyd.demo.entity.User;

public class LibraryImpl extends Library {
    private String name; // 书名 - 内部状态
    public LibraryImpl(String name) {
        this.name = name;
    }
    @Override
    public void borrow(User user) {
        System.out.println("图书馆的书《" + name + "》已被[" + user.getName() + "]借出");
    }
}

外部状态-User实体类

package com.lyd.demo.entity;

public class User {
    private String name;
    public User(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

工厂类
用Map集合来充当缓冲池,存放对象,并且提供获取对象的方法,为了方便观察享元模式的作用,还有个获取对象池中对象数量。

package com.lyd.demo.factory;
import com.lyd.demo.flyweight.Library;
import com.lyd.demo.flyweight.LibraryImpl;
import java.util.HashMap;

public class LibraryFactory {
    // 用集合来充当缓存池,暂存书籍
    private HashMap<String, LibraryImpl> pool = new HashMap<String, LibraryImpl>();
    // 如果有书籍就放入缓存
    public Library getLibraryImpl(String name) {
        if (!pool.containsKey(name)) {
            // 创建一个放入
            pool.put(name, new LibraryImpl(name));
        }
        return pool.get(name);
    }
    // 获取书籍个数
    public int bookCount() {
        return pool.size();
    }
}

测试
通过工厂类调用获得对象,再去调用借书方法,采用两种不用角色和不同数据来演绎享元模式的案例实现。

package com.lyd.demo.test;

import com.lyd.demo.entity.User;
import com.lyd.demo.factory.LibraryFactory;
import com.lyd.demo.flyweight.Library;

public class FlyWeightTest {
    public static void main(String[] args) {
        // 创建工厂
        LibraryFactory libraryFactory = new LibraryFactory();
        Library book = libraryFactory.getLibraryImpl("Java设计模式");
        book.borrow(new User("怒放吧德德"));

        // 假设书已经归还

        Library book2 = libraryFactory.getLibraryImpl("Java设计模式");
        book2.borrow(new User("愤怒吧德德"));

        Library book3 = libraryFactory.getLibraryImpl("Go语言编程");
        book3.borrow(new User("怒放吧德德"));

        System.out.println("现在有书:" + libraryFactory.bookCount() + " 本");
    }
}

运行结果:
在这里插入图片描述

4.享元模式优缺点

享元模式的主要优点和缺点如下:

优点:

  1. 减少内存占用:享元模式通过共享相同或相似的对象,可以在内存中只保存一份,从而节约系统资源,提高系统性能。
  2. 提高代码复用性:享元模式使得相同的对象可以被多个客户端共享使用,提高了代码的复用性。

缺点:

  1. 提高了系统的复杂性:享元模式需要分离出内部状态和外部状态,而且外部状态具有固化性,不应该随着内部状态的改变而改变,这使得程序逻辑复杂化。
  2. 需要维护一个存储享元对象的享元池:为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。

总的来说,享元模式适用于有大量相同或相似对象的系统,通过共享对象可以减少内存占用和提高代码复用性。但需要注意其增加系统复杂性和需要维护享元池的缺点。

5.享元模式适用场景

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

  1. 系统有大量相似对象,需要缓冲池的场景。比如游戏中的地图元素、图形绘制中大量相似图形等。
  2. 对于文本编辑器、网页渲染等需要处理大量重复内容的场景,可以使用享元模式提高性能。

在这些场景下,享元模式通过共享对象,可以减少内存占用和提高性能。

6.享元模式总结

     享元模式是一种用于优化内存占用和提高性能的设计模式。它通过共享相同或相似的对象,减少内存占用,提高系统的性能和代码的复用性。在使用享元模式时,需要注意分离出内部状态和外部状态,维护一个存储享元对象的享元池,并处理好对象的共享和独立状态。享元模式适用于有大量相同或相似对象的系统,可以提高系统的性能和可扩展性。

如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏 🙌一起讨论
你的支持就是我✍️创作的动力! 💞💞💞

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农桶子哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值