享元模式

news2024/11/26 16:25:11

文章目录

    • 享元模式
      • 1.享元模式的本质
      • 2.何时选用享元模式
      • 3.优缺点
      • 4.享元模式的结构
      • 5.实现
        • 最初实现
        • 享元模式初步改造
        • 享元模式再改进
        • 享元模式再优化

享元模式

享元模式最开始看就是类似缓存,缓存一些信息,节约查询时间,以空间换时间
但是再理解后才发现他的好处,他可以细粒化对象,抽离内部状态和外部状态来优化缓存

1.享元模式的本质

享元模式的本质:分离与共享。

分离的是对象状态中变与不变的部分,共享的是对象中不变的部分。享元模式的关键之处就在于分离变与不变,把不变的部分作为享元对象的内部状态,而变化部分则作为外部状态,由外部来维护,这样享元对象就能够被共享,从而减少对象数量,并节省大量的内存空间。

2.何时选用享元模式

  • 如果一个应用程序使用了大量的细粒度对象,可以使用享元模式来减少对象数量。
  • 如果由于使用大量的对象,造成很大的存储开销,可以使用享元模式来减少对象数量,并节约内存。
  • 如果不考虑对象的外部状态,可以用相对较少的共享对象取代很多组合对象,可以使用享元模式来共享对象,然后组合对象来使用这些共享对象。
  • 如果不考虑对象的外部状态,可以用相对较少的共享对象取代很多组合对象,可以使用享元模式来共享对象,然后组合对象来使用这些共享对象。

3.优缺点

享元模式的优点是:减少对象数量,节省内存空间。

  • 可能有的朋友认为共享对象会浪费空间,但是如果这些对象频繁使用,那么其实是·节省空间的。因为占用空间的大小等于每个对象实例占用的大小再乘以数量,对于享元对象来讲,基本上就只有一个实例,大大减少了享元对象的数量,并节省不少的内存空间。
    节省的空间取决于以下几个因素:因为共享而减少的实例数目、每个实例本身所占用的空间。假如每个对象实例占用2个字节,如果不共享数量是100个,而共享后就只有一个了,那么节省的空间约等于(100-1)×2字节。

享元模式的缺点是:维护共享对象,需要额外开销。

  • 如同前面演示的享元工厂,在维护共享对象的时候,如果功能复杂,会有很多额外的开销,比如有一个线程来维护垃圾回收。

4.享元模式的结构

在这里插入图片描述

  • Flyweight:享元接口,通过这个接口 Flyweight可以接受并作用于外部状态。通过这个接口传入外部的状态,在享元对象的方法处理中可能会使用这些外部的数据。
  • ConcreteFlyweight:具体的享元实现对象,必须是可共享的,需要封装 Flyweight的内部状态。
  • UnsharedConcreteFlyweight:非共享的享元实现对象,并不是所有的 Flyweight实现对象都需要共享。非共享的享元实现对象通常是对共享享元对象的组合对象。
  • FlyweightFactory:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。
  • Client:享元客户端,主要的工作是维持一个对Flyweight的引用,计算或存储享元对象的外部状态,当然这里可以访问共享和不共享的Flyweight对象。

5.实现

现有6个客户想各自做一个网站,整体结构相同,但归属不同客户

  • 有的客户希望是新闻发布形式的

  • 有的客户希望是博客形式的

  • 有的客户希望是公众号形式的等等

最初实现

1.网站类

/**
 * @description:网站类
 */
@AllArgsConstructor
public class WebSite {

    private String name = "";

    public void init() {
        System.out.println("当前网站分类: " + name);
    }
}

2.测试类

public class Test {

    public static void main(String[] args) {
        WebSite webSite1 = new WebSite("博客");
        webSite1.init();

        WebSite webSite2 = new WebSite("博客");
        webSite2.init();

        WebSite webSite3 = new WebSite("博客");
        webSite3.init();

        WebSite webSite4 = new WebSite("新闻发布");
        webSite4.init();

        WebSite webSite5 = new WebSite("公众号");
        webSite5.init();

        WebSite webSite6 = new WebSite("公众号");
        webSite6.init();
    }
}

3.结果
在这里插入图片描述

享元模式初步改造

1.网站接口及其实现类(也可不要接口)

/**
 * @description:网站接口
 */
public interface WebSite {

    /**
     * 初始化网站
     */
    void init();
}

/**
 * @description:网站实现类
 */
@AllArgsConstructor
public class ConcreteWebSite implements WebSite {

    /**
     * 网站类型
     */
    private String type;

    @Override
    public void init() {
        System.out.println("当前网站分类: " + type);
    }
}

2.网站工厂类

/**
 * @description:网站工厂
 */
public class WebSiteFactory {

    /**
     * 缓存网站对象
     */
    private Map<String, WebSite> map = new HashMap<>();

    /**
     * 获取网站对象
     * @param type 网站类型
     * @return
     */
    public WebSite getWebSiteCategory(String type) {
        //存在这个类型的网站就直接返回,不存在就新建放入map中缓存起来
        if (map.get(type) == null) {
            map.put(type, new ConcreteWebSite(type));
        }
        return map.get(type);
    }

    /**
     * 统计缓存的网站对象数量
     * @return
     */
    public Integer getWebSiteCount() {
        return map.size();
    }
}

3.测试类

public class Client {

    public static void main(String[] args) {
        // 创建一个工厂
        WebSiteFactory factory = new WebSiteFactory();

        // 给客户创建一个博客类型的网站
        WebSite webSite1 = factory.getWebSiteCategory("博客");
        webSite1.init();

        // 给客户创建一个博客类型的网站
        WebSite webSite2 = factory.getWebSiteCategory("博客");
        webSite2.init();

        // 给客户创建一个博客类型的网站
        WebSite webSite3 = factory.getWebSiteCategory("博客");
        webSite3.init();

        // 给客户创建一个新闻发布类型的网站
        WebSite webSite4 = factory.getWebSiteCategory("新闻发布");
        webSite4.init();

        // 给客户创建一个公众号类型的网站
        WebSite webSite5 = factory.getWebSiteCategory("公众号");
        webSite5.init();

        // 给客户创建一个公众号类型的网站
        WebSite webSite6 = factory.getWebSiteCategory("公众号");
        webSite6.init();

        // 查看实例数
        System.out.println("实例数:" + factory.getWebSiteCount());
    }
}

4.结果
在这里插入图片描述
可以看到只创建了3个对象,而最初的写法创建了6个对象,现在看可能提升不明显,但如果是需要创建100个对象,1000个对象呢?

享元模式再改进

上面创建三个博客类型的网站,但是好像这三个网站就是一模一样的,但是不同的客户,所以加上网站归属用户,再改造

1.接口不变

2.实现类增加客户名属性

/**
 * @description:网站实现类
 */
@AllArgsConstructor
public class ConcreteWebSite implements WebSite {

    /**
     * 网站类型
     */
    private String type;

    /**
     * 网站归属用户
     */
    private String userName;

    @Override
    public void init() {
        System.out.println("当前网站分类: " + type + " 【客户】: " + userName);
    }
}

3.网站工厂类,现在有两个属性(网站类型、客户名),用他俩一起做键

/**
 * @description:网站工厂
 */
public class WebSiteFactory {

    /**
     * 缓存网站对象
     */
    private Map<String, WebSite> map = new HashMap<>();

    /**
     * 获取网站对象
     * @param type 网站类型
     * @return
     */
    public WebSite getWebSiteCategory(String type, String userName) {
        //用"客户:类型"做键
        String key = userName + ":" + type;
        //存在这个类型的网站就直接返回,不存在就新建放入map中缓存起来
        if (map.get(key) == null) {
            map.put(key, new ConcreteWebSite(type, userName));
        }
        return map.get(key);
    }

    /**
     * 统计缓存的网站对象数量
     * @return
     */
    public Integer getWebSiteCount() {
        return map.size();
    }
}

4.测试类

public class Client {

    public static void main(String[] args) {
        // 创建一个工厂
        WebSiteFactory factory = new WebSiteFactory();

        // 给客户创建一个博客类型的网站
        WebSite webSite1 = factory.getWebSiteCategory("博客", "客户A");
        webSite1.init();

        // 给客户创建一个博客类型的网站
        WebSite webSite2 = factory.getWebSiteCategory("博客", "客户B");
        webSite2.init();

        // 给客户创建一个博客类型的网站
        WebSite webSite3 = factory.getWebSiteCategory("博客", "客户C");
        webSite3.init();

        // 给客户创建一个新闻发布类型的网站
        WebSite webSite4 = factory.getWebSiteCategory("新闻发布", "客户A");
        webSite4.init();

        // 给客户创建一个公众号类型的网站
        WebSite webSite5 = factory.getWebSiteCategory("公众号", "客户B");
        webSite5.init();

        // 给客户创建一个公众号类型的网站
        WebSite webSite6 = factory.getWebSiteCategory("公众号", "客户C");
        webSite6.init();

        // 查看实例数
        System.out.println("实例数:" + factory.getWebSiteCount());
    }
}

5.结果
在这里插入图片描述
可以看到又是6个对象了,那这样用不用设计模式都一样了

享元模式再优化

从上面结果可以发现,网站其实只有3种类型(博客、新闻发布、公众号),只是归属不同的客户,那么可以拆分,将网站类型作为内部状态,客户作为外部状态,再改造

  • 内部状态:对象共享出来的信息,存储在享元对象内部并且不会随环境改变的共享部分

  • 外部状态:对象用来标记的一个内容,随环境会改变,不可共享

1.改造网站接口及其实现类,在调用方法时传入客户名

/**
 * @description:网站接口
 */
public interface WebSite {

    /**
     * 初始化网站传入客户名
     * @param userName 客户名
     */
    void init(String userName);
}

/**
 * @description:网站实现类
 */
@AllArgsConstructor
public class ConcreteWebSite implements WebSite {

    /**
     * 网站类型
     */
    private String type;

    @Override
    public void init(String userName) {
        System.out.println("当前网站分类: " + type + " 【客户】: " + userName);
    }
}

2.网站工厂类不变

/**
 * @description:网站工厂
 */
public class WebSiteFactory {

    /**
     * 缓存网站对象
     */
    private Map<String, WebSite> map = new HashMap<>();

    /**
     * 获取网站对象
     * @param type 网站类型
     * @return
     */
    public WebSite getWebSiteCategory(String type) {
        //存在这个类型的网站就直接返回,不存在就新建放入map中缓存起来
        if (map.get(type) == null) {
            map.put(type, new ConcreteWebSite(type));
        }
        return map.get(type);
    }

    /**
     * 统计缓存的网站对象数量
     * @return
     */
    public Integer getWebSiteCount() {
        return map.size();
    }
}

3.测试类

public class Client {

    public static void main(String[] args) {
        // 创建一个工厂
        WebSiteFactory factory = new WebSiteFactory();

        // 给客户创建一个博客类型的网站
        WebSite webSite1 = factory.getWebSiteCategory("博客");
        webSite1.init("客户A");

        // 给客户创建一个博客类型的网站
        WebSite webSite2 = factory.getWebSiteCategory("博客");
        webSite2.init("客户B");

        // 给客户创建一个博客类型的网站
        WebSite webSite3 = factory.getWebSiteCategory("博客");
        webSite3.init("客户C");

        // 给客户创建一个新闻发布类型的网站
        WebSite webSite4 = factory.getWebSiteCategory("新闻发布");
        webSite4.init("客户A");

        // 给客户创建一个公众号类型的网站
        WebSite webSite5 = factory.getWebSiteCategory("公众号");
        webSite5.init("客户B");

        // 给客户创建一个公众号类型的网站
        WebSite webSite6 = factory.getWebSiteCategory("公众号");
        webSite6.init("客户C");

        // 查看实例数
        System.out.println("实例数:" + factory.getWebSiteCount());
    }
}

4.结果
在这里插入图片描述
这样将不变的信息作为内部状态,将不确定的信息作为外部状态,这就是享元模式的最终模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/88868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一行代码就能完成的事情,为什么要写两行

今天休息休息&#xff0c;复习一下使用的简洁运算方式以及常用的单行代码 三元运算符 用三元运算符代替简单的if else if (age < 18) {me 小姐姐; } else {me 老阿姨; } 改用三元运算符,一行就能搞定 me age < 18 ? 小姐姐 : 老阿姨; 复杂的判断三元运算符就有点…

这才是最适合新手的python教程(最新版python3.10)

前言 这几年&#xff0c;Python 凭借着语法简洁、跨平台、类库丰富、可扩展、开放源码等特点&#xff0c;成为了 AI 和机器学习时代的第一编程语言。甚至击破铁三角&#xff08; Java、C、C&#xff09;的架构&#xff0c;荣登 TIOBE 榜单的榜首。 身边有不少程序员都选择 Pyt…

LEADTOOLS 入门教程: 检测和提取条形码 - .NET Core

LEADTOOLS是一个综合工具包的集合&#xff0c;用于将识别、文档、医疗、成像和多媒体技术整合到桌面、服务器、平板电脑、网络和移动解决方案中&#xff0c;是一项企业级文档自动化解决方案&#xff0c;有捕捉&#xff0c;OCR&#xff0c;OMR&#xff0c;表单识别和处理&#x…

漏洞丨PDF Explorer 1.5.66.2 - Buffer Overflow

作者&#xff1a;黑蛋 一、漏洞简介 这是一个栈溢出漏洞&#xff0c;一个叫PDF Explorer的软件&#xff08;干嘛的咱没必要知道&#xff09;&#xff0c;他对于用户输入内容长度没有限制造成栈溢出漏洞。 二、漏洞环境 虚拟机 目标程序 调试器 win7x86 PDF Explorer x32…

NeurIPS 2022 | MoVQ: 基于Modulating Quantized Vectors的高保真图像生成

原文标题&#xff1a;MoVQ: Modulating Quantized Vectors for High-Fidelity Image Generation 一、问题提出 虽然两级Vector Quantized (VQ)【指VQVAE-2】生成模型允许合成高保真和高分辨率图像&#xff0c;但它们的量化操作符将图像中的相似patch编码到相同的索引中&#…

2023年MBA联考英语(二)大作文:关于某高校大学生的十大主题

2023年管理类联考倒计时9天&#xff01;在历年的联考英语二作文主题中&#xff0c;大学生群体是时长会出现一期的&#xff0c;这既是对联考中部分专业涉及大学生群体的一种反映&#xff0c;也是因为这个群体的话题对大多数考生来讲都相对熟悉&#xff0c;毕竟都是从这个阶段经历…

世界杯竞猜项目Dapp-第四章(subgraph)

subgraph 是什么 subgraph 索引协议作为 Dapp 领域最重要的基建之一&#xff08;如 uniswap、wave 等都在使用&#xff09;&#xff0c;主要用来做链上数据索引&#xff0c;即在链下对链上事件进行捕捉&#xff08;扫链、计算、存储&#xff09;&#xff0c;然后可对存储下来的…

CAN总线学习笔记 | CAN盒测试STM32的CAN中断接收

CAN基础知识介绍文中介绍了CAN协议的基础知识&#xff0c;以及STM32F4芯片的CAN控制器相关知识&#xff0c;下面将通过实例&#xff0c;利用STM32CubeMX图形化配置工具&#xff0c;并配合CAN盒&#xff0c;来实现CAN通讯的中断收发测试 一、STM32CubeMX配置 CAN是挂载在APB1总…

《钱进球场》:球场争锋·棒球1号位

动画《钱进球场》改编自森高夕次原作、足立刑事著同名体育漫画&#xff0c;于2017年3月宣布动画化 &#xff0c;由STUDIO DEEN负责动画制作&#xff0c;于2018年4月6日起播出。动画第二期于2018年10月5日开始播出。全24话。 中文名 钱进球场 原版名称 グラゼニ 动画制作 Stud…

pytorch 生成手写数字图像

生成对抗网络的概念 最基本的GAN模型由一个生成器 G 和判别器 D 组成。生成器用于生成假样本&#xff0c;判别器用于判断样本是真实的还是假的。 生成器(Generator)&#xff1a;通过机器生成数据&#xff08;大部分情况下是图像&#xff09;&#xff0c;目的是“骗过”判别器…

jQuery - AJAX 简介

什么是 AJAX&#xff1f; AJAX 异步 JavaScript 和 XML&#xff08;Asynchronous JavaScript and XML&#xff09;。 简短地说&#xff0c;在不重载整个网页的情况下&#xff0c;AJAX 通过后台加载数据&#xff0c;并在网页上进行显示。 使用 AJAX 的应用程序案例&#xff…

个人简介网页设计作业 静态HTML个人介绍网页作业 DW个人网站模板下载 WEB静态大学生简单网页 个人网页作品代码 个人网页制作 学生个人网页

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

[附源码]Nodejs计算机毕业设计基于百度AI平台的财税报销系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Redis中BIO、NIO、IO多路复用

1 BIO(阻塞IO) 阻塞IO就是两个阶段都必须阻塞等待 通常IO操作都是阻塞I/O的&#xff0c;也就是说当你调用read时&#xff0c;如果没有数据收到&#xff0c;那么线程或者进程就会被挂起&#xff0c;直到收到数据。 read直到数据复制到应用进程的缓冲区或者发生错误才会返回&am…

【数据结构与算法】第十六篇:图论(基础篇)

知识导航图形结构的引进图&#xff08;Grapth&#xff09;1.图的概念与应用2.有向图入度&#xff0c;出度3.无向图4.完全图无向完全图有向完全图5.连通图6.连通分量强连通分量图的实现方案1.邻接矩阵实现法2.邻接表实现法3.两种方法对比分析图形结构的引进 &#x1f30e; 数据…

Linux基础-目录操作

该文章主要为完成实训任务及总结&#xff0c;详细实现过程及结果见【参考文章】 参考文章&#xff1a;https://howard2005.blog.csdn.net/article/details/126962205 文章目录一、常用权限操作1.1 常用权限操作1. chgrp命令2. chown命令3. chmod命令1.2 权限操作实战任务1 创建…

14、Redis_主从复制

文章目录14、Redis_主从复制14.1 是什么14.2. 能干嘛14.3 怎么玩&#xff1a;主从复制14.3.1 新建redis6379.conf&#xff0c;填写以下内容14.3.2 新建redis6380.conf&#xff0c;填写以下内容14.3.3 新建redis6381.conf&#xff0c;填写以下内容14.3.4 启动三台redis服务器14.…

java项目_第173期ssm高校二手交易平台_计算机毕业设计

java项目_第173期ssm高校二手交易平台_计算机毕业设计 【源码请到下载专栏下载】 今天分享的项目是《ssm高校二手交易平台》 该项目分为2个角色&#xff0c;管理员和用户。 用户可以浏览前台商品&#xff0c;并且进行购买商品&#xff0c;并在 个人后台查看自己的订单、查看商品…

DPDK源码分析之DPDK技术简介

Cache和内存技术 1. Cache一致性 多核处理器同时访问同一段cacheline时&#xff0c;会出现写回冲突的情况&#xff0c;操作系统解决这个问题会消耗一部分性能&#xff0c;DPDK采用了两个技术来解决这个问题&#xff1a; 对于共享的数据&#xff0c;每个核都定义自己的备份lc…

区块链学习2-合约开发

概述 智能合约本质上是运行在某种环境&#xff08;例如虚拟机&#xff09;中的一段代码逻辑。 长安链的智能合约是运行在长安链上的一组“动态代码”&#xff0c;类似于Fabric的chaincode&#xff0c;Fabric的智能合约称为链码&#xff08;chaincode&#xff09;&#xff0c;…