设计模式(22)享元模式

一、介绍:

1、定义:享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

2、组成结构:

(1)Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。

public abstract class  Flyweight{public abstract void operation(String extrinsicState);
}

(2)ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。

public class ConcreteFlyweight extends Flyweight{//内部状态intrinsicState作为成员变量,同一个享元对象的内部状态是一致的private String intrinsicState;public ConcreteFlyweight(String intrinsicState){this.intrinsicState = intrinsicState;}//外部状态extrinsicState在使用时由外部设置,不保存在享元对象中,即使是同一个对象//在每一次调用时可以传入不同的外部状态public void operation(String extrinsicState){//实现业务方法}
}

(3)UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

public class UnsharedConcreteFlyweight extends Flyweight{public void operation(String extrinsicState){//实现业务方法}
}

(4)FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),返回新创建的实例并将其存储在享元池中。

public class FlyweightFactory{//定义一个HashMap用于存储享元对象,实现享元池private HashMap flyweights = new HashMap();public Flyweight getFlyweight(String key){//如果对象存在,则直接从享元池获取if(flyweight.containsKey(key)){return (Flyweight)flyweight.get(key);}//如果对象不存在,先创建一个新的对象添加到享元池中,然后返回else{Flyweight fw = new ConcreteFlyweight();flyweights.put(key,fw);return fw;}}
}

3、享元模式将对象的状态分为内部状态和外部状态:

(1)内部状态:是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变,如用户的ID、Name,它们可以作为一个对象的动态附加信息,不必直接储存在具体某个对象中,属于可以共享的部分。即在生成对象后,类的属性每个对象都不一样,那他就是内部状态,用户的ID是每个用户都不一样的。

(2)外部状态:是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态,它是一批对象的统一标识,是唯一的一个索引值。即在生成对象后,类的属性大部分对象或部分的值相同,那么这个属性就是外部状态,例如用户属于VIP用户,很多用户都属于VIP用户。

4、优缺点:

优点:

(1)减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率

(2)减少内存之外的其他资源占用 (减少new 关键字的创建次数)

缺点:

(1)关注内/外部状态、关注线程安全问题

(2)使系统、程序的逻辑复杂化

5、相关设计模式:

(1)代理模式:代理模式是需要代理一个类,需要生成的代理类花费的资源和时间比较多就可以使用享元模式提高;

(2)单例模式:容器单例模式就是享元模式和单例模式的结合,使用复用的思想提高程序的使用频率。

6、使用场景:

二、demo:

1、黑白棋:黑白棋游戏需要大量的棋子对象,如果为每一个棋子都单独创建一个对象,系统的性能和内存开销都非常大。使用享元模式,可以将一些相同的棋子对象共享起来,只需要保存其内部和外部状态区分即可。

/*** 抽象的棋子接口*/
public interface Piece {void put(int x, int y);
}/*** 黑棋类*/
public class BlackPiece implements Piece {@Overridepublic void put(int x, int y) {System.out.println("在坐标 (" + x + ", " + y + ") 放置了一个黑棋子");}
}/*** 白棋类*/
public class WhitePiece implements Piece {@Overridepublic void put(int x, int y) {System.out.println("在坐标 (" + x + ", " + y + ") 放置了一个白棋子");}
}

//棋子享元工厂类
public class PieceFactory {private final Map<String, Piece> map = new HashMap<>();public Piece getPiece(String color) {Piece piece = map.get(color);if (piece == null) {switch (color) {case "black":piece = new BlackPiece();break;case "white":piece = new WhitePiece();break;default:throw new IllegalArgumentException("Unsupported color: " + color);}map.put(color, piece);}return piece;}
}
//客户端public static void main(String[] args) {PieceFactory factory = new PieceFactory();Piece black1 = factory.getPiece("black");black1.put(1, 1);Piece black2 = factory.getPiece("black");black2.put(2, 2);Piece white1 = factory.getPiece("white");white1.put(3, 3);Piece white2 = factory.getPiece("white");white2.put(4, 4);}输出:
在坐标 (1, 1) 放置了一个黑棋子
在坐标 (2, 2) 放置了一个黑棋子
在坐标 (3, 3) 放置了一个白棋子
在坐标 (4, 4) 放置了一个白棋子

2、扑克牌游戏:54张扑克牌(1到13四种花色)+大王+小王:

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows下多Chrome谷歌浏览器版本共存

场景 某些年代久远的 WEB 应用&#xff0c;必须在指定的浏览器或版本才能正常运行&#x1f602;&#xff0c;此时就需要多个版本 chrome 浏览器共存。 解决方案 下载指定版本 可以从 https://www.chromedownloads.net/ 下载需要的版本&#xff0c;此处下载的是87.0.4280.14…

【Servlet】 一

本文主要介绍了如何在tomcat部署一个webapp 以及 如何借助maven用servlet编写一个hello world . 一.Tomcat Tomcat是一个Java里广泛使用的http服务器 HTTP服务器有很多实现&#xff0c;其中最知名的是Nginx&#xff1b;而在Java里&#xff0c;最知名的是Tomcat 一个Tomcat服务…

快速入手maven

文章目录 Maven介绍Maven安装和配置基于IDEA的Maven工程创建梳理Maven工程GAVP属性Idea构建Maven JavaSE工程Idea构建Maven JavaEE工程1. 手动创建2. 插件方式创建 Maven工程项目结构说明Maven核心功能依赖和构建管理依赖传递和冲突依赖导入失败场景和解决方案扩展构建管理和插…

HDFS架构介绍

数新网络_让每个人享受数据的价值浙江数新网络有限公司是一家开源开放、专注于云数据智能操作系统和数据价值流通的服务商。公司自主研发的DataCyber云数据智能操作系统&#xff0c;主要包括数据平台CyberData、人工智能平台CyberAI、数据智能引擎CyberEngine、数据安全平台Cyb…

振弦传感器智能化:电子标签模块

振弦传感器智能化&#xff1a;电子标签模块 稳控科技研发并批量生产的振弦采集模块解决了传感器由模拟信号直接转变为数字信号的难题。近年来&#xff0c;振弦传感器为适应用户需求&#xff0c;不断迭代更新技术&#xff0c;使学习和使用成本非常低&#xff0c;且带来方便快捷…

创建超过1G内存大小的程序

正常情况一个进程最大占用内存为1G一下&#xff0c;如果程序有需求要使用超过1G大小的程序&#xff0c;可进行如下操作 VS修改设置&#xff1a;属性--->链接器--->系统--->启用大地址 【选择是】 测试申请堆内存代码 #include <stdlib.h> #include <stdio…

redis 网课笔记

缓存 缓存雪崩 缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机&#xff0c;导致大量请求到达数据库。 解决方案 给不同的key的TTL添加随机值利于Redis集群提高服务的可用性 哨兵模式、集群模式给缓存业务添加降级限流策略 ngxin或spring cloud gateway给业务…

05 # 手写 bind

bind 干了什么&#xff1f; 改变 this 指向没有让函数执行&#xff0c;返回一个改变 this 指向后的函数 bind 难点在于参数的收集 手写 bind 简单实现如下&#xff1a; <script>Function.prototype.kaimoBind function (content) {// 获取到 bind 里的剩余参数let …

Linux C语言进阶-D3~D4字符串处理函数

求字符串长度函数strlen、字符串拷贝strcpy、字符串连接strcat、字符串比较strcmp 头文件<string.h> 求字符串长度strlen函数 1、计算字符串长度&#xff0c;并且遇到\0结束&#xff0c;返回字符串长度 2、 计算字符串长度&#xff0c;遇到转义字符&#xff0c;\不算在内…

EVM6678L 开发教程: IBL-TFTP 引导 elf 文件

目录 EVM6678L 开发教程: IBL-TFTP 引导 elf 文件安装 Tftpd64测试工程测试说明 EVM6678L 开发教程: IBL-TFTP 引导 elf 文件 参考: "C:\ti\mcsdk_2_01_02_06\tools\boot_loader\examples\i2c\tftp\docs\README.txt" 此教程介绍如何在 EVM6678L 开发板上实现 IBL-…

开关电源测试过压保护的测试标准及其方法

过压保护的原理 过压保护是电压超过预定值时降低电压的一种方式&#xff0c;原理是通过电路中的电压检测电路来检测电路中的电压是否超过了设定的阈值&#xff0c;如果超过了阈值&#xff0c;就会触发过压保护器件&#xff0c;使电源断开或使受控设备电压降低&#xff0c;保护电…

docker--基本操作

第 1 章 Docker基础 1.1 docker简介 在这一部分我们主要讲两个方面&#xff1a; docker是什么、docker特点 1.1.1 docker是什么 docker是什么&#xff1f; docker的中文解释是码头工人。 官方解释&#xff1a; Docker是一个开源的容器引擎&#xff0c;它基于LCX容器技术&…