设计模式篇---享元模式

文章目录

    • 概念
    • 结构
    • 实例
    • 总结

概念

享元模式:运用共享技术有效地支持大量细粒度对象的复用。
当系统中出现大量相同或者相似的对象时,可以考虑使用享元模式。享元模式中提供了一个享元池用于存储已经创建好的对象。享元对象能做到共享的关键是区分了内部状态和外部状态。
内部状态:内部状态是存储在享元对象内部并且不会随环境改变而改变。
外部状态:外部状态是随环境改变而改变的、不可共享的状态。
举个例子,比如五子棋的大小形状就是内部状态,它不会随着环境而改变,而五子棋的位置就是外部状态

结构

在这里插入图片描述享元,就是共享元素的意思。但是英文名字叫做FlyWeight,翻译成中文也不叫享元,直接翻译大概意思是轻量级的意思。

FlyWeight(抽象享元类):声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部状态,也可以通过这些方法设置外部状态。
ConcreteFlyweight(具体享元类):具体享元类实现了抽象享元类,在具体享元类中为内部状态提供了存储空间。
UnsharedConcreteFlyweight(非共享具体享元类):不能共享的子类可设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
FlyweightFactory(享元工厂类):用于创建并管理享元对象,将各种类型的具体享元对象存储在一个享元池中。当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在),返回新创建的实例并将其存储在享元池中。

实例

现在要开发一个围棋软件。棋盘中有大量的黑子和白子,它们的形状、大小一样,只是位置不同。现在用享元模式来完成这个demo。
在这里插入图片描述
IgoChessman 类,抽象享元类。

public abstract class IgoChessman {

    public abstract String getColor();

    public void display(){
        System.out.println("棋子颜色:" + this.getColor());
    }

}

黑色围棋类。

public class BlackIgoChessman extends IgoChessman{
    @Override
    public String getColor() {
        return "黑色";
    }
}

黑色围棋类。

public class WhiteIgoChessman extends IgoChessman {
    @Override
    public String getColor() {
        return "白色";
    }
}

围棋棋子工厂类。

public class IgoChessmanFactory {
   //饿汉式单例类
    private static IgoChessmanFactory instance = new IgoChessmanFactory();
    private static Hashtable ht;

    private IgoChessmanFactory() {
        ht = new Hashtable();
        IgoChessman black, white;
        black = new BlackIgoChessman();
        ht.put("b", black);
        white = new WhiteIgoChessman();
        ht.put("w", white);
    }

    //返回唯一实例
    public static IgoChessmanFactory getInstance() {
        return instance;
    }

    //获取享元对象
    public static IgoChessman getIgoChessman(String color) {
        return (IgoChessman) ht.get(color);
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        IgoChessman black1,black2,black3,white1,white2;
        IgoChessmanFactory factory;
        //获取享元工厂对象
        factory = IgoChessmanFactory.getInstance();
        //通过享元工厂获取三颗黑子
        black1 = factory.getIgoChessman("b");
        black2 = factory.getIgoChessman("b");
        black3 = factory.getIgoChessman("b");
        System.out.println("判断两颗黑子是否相同:" + (black1==black2));
        //通过享元工厂获取两颗白子
        white1 = factory.getIgoChessman("w");
        white2 = factory.getIgoChessman("w");
        System.out.println("判断两颗白子是否相同:" + (white1==white2));
        //显示棋子
        black1.display();
        black2.display();
        black3.display();
        white1.display();
        white2.display();
    }

}

打印结果:
在这里插入图片描述
上面是没有外部状态的享元模式,如果有外部状态,如围棋需要加一个坐标类。
坐标类代码

public class Coordinates {
    private int x;
    private int y;
    
    public Coordinates(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public Coordinates() {
    }
    
    public int getX() {
        return x;
    }
    
    public Coordinates setX(int x) {
        this.x = x;
        return this;
    }
    
    public int getY() {
        return y;
    }
    
    public Coordinates setY(int y) {
        this.y = y;
        return this;
    }
}

然后再修改一下IgoChessman,依赖坐标对象

public abstract class IgoChessman {

    public abstract String getColor();

    public void display(Coordinates coordinates){
        System.out.println("棋子颜色:" + this.getColor() + ",棋子位置:" + coordinates.getX() + "," + coordinates.getY());
    }

}

客户端代码修改

public class Client {
    public static void main(String[] args) {
        IgoChessman black1,black2,black3,white1,white2;
        IgoChessmanFactory factory;
        //获取享元工厂对象
        factory = IgoChessmanFactory.getInstance();
        //通过享元工厂获取三颗黑子
        black1 = factory.getIgoChessman("b");
        black2 = factory.getIgoChessman("b");
        black3 = factory.getIgoChessman("b");
        System.out.println("判断两颗黑子是否相同:" + (black1 == black2));
        //通过享元工厂获取两颗白子
        white1 = factory.getIgoChessman("w");
        white2 = factory.getIgoChessman("w");
        System.out.println("判断两颗白子是否相同:" + (white1 == white2));
        //显示棋子
        black1.display(new Coordinates(1,2));
        black2.display(new Coordinates(3,4));
        black3.display(new Coordinates(1,3));
        white1.display(new Coordinates(2,5));
        white2.display(new Coordinates(2,4));
    }

}

打印结果:
在这里插入图片描述

总结

当需要创建大量重复对象的时候,可以考虑使用享元模式。java中的String类,也是用了享元模式。当我们创建一个字符串,如果这个字符串对象第一次创建的话,就会放到享元池中,下次再创建内容相同的字符串对象,新创建的对象就会将它的引用指向第一次创建的对象,不会分配新的内存,以此来实现字符串的共享。

    String str1 = "abcd";
        String str2 = "abcd";
        String str3 = "ab" + "cd";
        String str4 = "ab";
        str4 += "cd";


        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
        System.out.println(str1 == str4);

打印结果:
在这里插入图片描述
第三个为false,是因为一开始str4是一个对象,和str1的初始值不同,所以这两个的地址是不一样的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Diary22-全网最全的CSS3.0讲解

CSS学习 1.认识CSS 1.1什么是CSS CSS:Cascading Style Sheet——层叠级联样式表 CSS:表现(美化网页) 字体;颜色;边距;高度;宽度;背景图片;网页定位&…

Nginx按指定格式记录访问日志以及利用logrotate做日志轮转

今天突然想起来一个日志的一个东西,因为拉项目无意中看到了日志文件的一些东西,现在不经常做后端了,加上其他的一些原因吧.有时候有些问题也没想太多,马马虎虎就过了,后来想想还是要记录一下这方面的处理过程吧: 一般我们作为开发人员关注的日志只是在应用程序层面的,我们称它…

springboot095学生宿舍信息的系统

springboot095学生宿舍信息的系统 源码获取: https://docs.qq.com/doc/DUXdsVlhIdVlsemdX

使用MfgTool烧写工具烧写自制系统

一. 简介 本文我们就来学习,如何将我们编译的 uboot,zImage(内核镜像),xxx.dtb设备树文件,还有制作的根文件系统,这四个文件烧写到开发板中,最后 开发板能正常启动。 上一篇文章说…

Linux权限(用户角色+文件权限属性)

Linux权限 文章目录 Linux权限一.文件权限1.快速掌握修改权限的方法(修改文件权限属性)2.对比权限的有无,以及具体的体现3.修改权限的第二套方法(修改用户角色)4.文件类型(Linux下一切皆文件) 二…

六级高频词汇1

目录 高频词汇 参考连接 高频词汇 1. alter v. 改变,改动,变更 2. burst vi. n. 突然发生,爆裂 3. dispose vi. 除掉;处置;解决;处理(of) 4. blast n. 爆炸;气流 vi. 炸,炸掉 …

Python轴承故障诊断 (五)基于EMD-LSTM的故障分类

目录 前言 1 经验模态分解EMD的Python示例 2 轴承故障数据的预处理 2.1 导入数据 2.2 制作数据集和对应标签 2.3 故障数据的EMD分解可视化 2.4 故障数据的EMD分解预处理 3 基于EMD-LSTM的轴承故障诊断分类 3.1 训练数据、测试数据分组,数据分batch 3.2 定…

C++ 面向对象补充

目录 初始化列表 explicit关键字 单参数构造函数 多参数构造函数 static成员 友元 内部类(不常用) 匿名对象 初始化列表 以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟 一个放在括号中的初始值或表达式。 class Date…

头歌平台题目参考

任务描述 本关任务:获取从键盘输入3个数,要求按从大到小的顺序输出这3个数。 相关知识 程序并不会总是执行同样的处理。例如,按下某个键的时候执行 A 处理,按下其他键的时候执行 B 处理…… 像这样,程序通过条件判断…

回溯算法之N皇后

一 什么是回溯算法 回溯算法(Backtracking Algorithm)是一种用于解决组合优化问题的算法,它通过逐步构建候选解并进行验证,以寻找所有满足特定条件的解。回溯算法通常应用于在给定约束条件下枚举所有可能解的问题,如…

FaceBook推出新的翻译模型Seamless!可实现跨语言交流的无缝衔接!

FaceBook **(中文名:脸书)**近期发布了一个新的翻译模型 Seamless Communication,可实现跨语言实时"无缝"交流。 该模型可以保留跨语言的表达方式和复杂性(翻译时保留语音中的停顿和语速,以及声…

优雅草蜻蜓I即时通讯·水银版私有化部署之安卓Android端编译-02

Android 项目配置 添加图片注释,不超过 140 字(可选) 使用以上Android studio版本 添加图片注释,不超过 140 字(可选) 下载最低sdk最低版本28 完成后就可以导入项目(项目导入不能开VPN,会导致部分三方库…

Glibc之malloc实现原理

前言导入 内存管理之虚拟内存空间 详细了解这部分知识,再看下面的内容会很舒服 进程地址空间 在32位Linux系统中,进程地址空间是这样分布的。其中内核空间独占1G,不允许用户操作,其余3G由用户操作。malloc的操作对象&#xff1…

C语言之函数设计(1)

目录 没有返回值的函数 通用性 不含形参的函数 函数返回值的初始化 作用域 文件作用域 声明和定义 函数原型声明 头文件和文件包含指令 在上节中我们简单的学习了函数的创建方法(函数定义)与函数的使用方法(函数调用)&…

谈一谈网络协议中的应用层

文章目录 一,什么是HTTPHTTP的优缺点HTTPS 一,什么是HTTP 我们在通过网络进行传输数据时,我们要保证,我们在发送时构造的数据,在接收时也能够解析出来,这本质上就是一种协议,是一种应用层协议&…

python zblog API实现类似XMLRPC/发布文章

我发现python对Zblog的XML发布并不友好,虽然也有对应的模块,但是远远没有XPCRPC更直接方便,但是使用xmlRpc是直接给发布文章带来了不小的便利,但是对系统也并不友好,但是zblog也开放了Api,但是干部子弟不乐…

测试剪切板贴图,兼测试2023年12月7日更新的Bard

当前的情况好比,(居然真的可以通过剪切板把图片放进来!) 听说2023年12月7日Bard有更新,所以,再测试了一次。这下,对大语言模型应该死心了;AI替代人的传闻应该是过早危言耸听了。

SAP UI5 walkthrough step3 Controls

在上一步&#xff0c;我们是直接用index.html 中的body 里面的DIVision去输出 hello world&#xff0c; 在这个章节&#xff0c;我们将用SAP UI5 的标准控件 sap/m/Text 首先&#xff0c;我们去修改 webapp/index.html <!DOCTYPE html> <html> <head><…

Vue3-02-ref() 响应式详解

ref() 是什么 ref() 是一个函数&#xff1b; ref() 函数用来声明响应式的状态&#xff08;就是来声明变量的&#xff09; ref() 函数声明的变量&#xff0c;是响应式的&#xff0c;变量的值改变之后&#xff0c;页面中会自动重新渲染。ref() 有什么特点 1.ref() 可以声明基础…

java服务调用mysql报错

一、前言 前端服务调用后端服务时出现以下报错&#xff0c;原因是使用mysql5.7版本数据库中存在ONLY_FULL_GROUP_BY这个配置项导致的不兼容 MySQLSyntaxErrorException: Expression #32 of SELECT list is not in GROUP BY clause and contains nonaggregated column demeter…