Java设计模式之结构型-享元模式(UML类图+案例分析)

news2024/11/24 17:50:35

目录

一、基本概念

二、UML类图

三、角色设计

四、案例分析

1、基本实现

2、游戏角色

五、总结


一、基本概念

享元模式是一种结构型设计模式,主要用于减少创建大量相似对象所占用的内存,它通过共享技术来有效支持大量细粒度的对象。

二、UML类图

三、角色设计

角色描述
抽象享元角色定义出对象的外部状态和内部状态的接口或属性。
具体享元角色实现抽象享元角色,定义内部状态,可以保存共享对象的状态
享元工厂角色负责创建和管理享元对象
客户端角色存储外部状态,在需要时通过享元工厂获取享元对象

四、案例分析

享元模式中的享元对象可以认为是一种可复用的组件。比如在游戏中,有许多类型相同的敌人,这时就可以使用享元模式。

1、我们会创建一个享元工厂类,这个类就像一个存放享元对象的仓库。客户端需要对象时,就来这个工厂类这里取。

2、工厂类存放的是享元对象。享元对象有两种状态:内部状态与外部状态。

内部状态是对象共享的部分,不会改变,比如敌人的形状、颜色等。

外部状态是对象依赖的可变部分,比如敌人的位置。

3、当客户端需要一个享元对象时,会先从工厂请求。 

如果工厂里已有该对象,就直接返回已有实例,复用该对象。 

如果没有,则创建新实例,并存入工厂后返回。

4、客户端拿到对象后,将外部状态设置给该对象,然后显示。

5、对象使用完后并不销毁,而是返还给工厂继续复用。这样通过管理可复用的享元对象,就可以大量减少对象的创建,节省内存空间,提高性能。

本篇共举了2个简单的小案例进行分析,可以更好的去理解这个设计模式。

1、基本实现

首先定义一个享元接口并声明了一个操作方法:

interface Flyweight {

    void operate(String extrinsicState);

}

创建具体的享元类,实现享元接口,并包含内部状态: 

class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;
 
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
 
    public void operate(String extrinsicState) {
        System.out.println("内部状态: " + intrinsicState);
        System.out.println("外部状态: " + extrinsicState);
        // 执行享元操作
    }
}

创建享元工厂类,用于管理和共享享元对象: 

import java.util.HashMap;
import java.util.Map;
 
class FlyweightFactory {
    private Map<String, Flyweight> flyweights;
 
    public FlyweightFactory() {
        flyweights = new HashMap<>();
    }
 
    public Flyweight getFlyweight(String intrinsicState) {
        if (flyweights.containsKey(intrinsicState)) {
            return flyweights.get(intrinsicState);
        } else {
            Flyweight flyweight = new ConcreteFlyweight(intrinsicState);
            flyweights.put(intrinsicState, flyweight);
            return flyweight;
        }
    }
}

在客户端中使用享元工厂类来获取和使用享元对象:

public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
 
        // 获取或创建享元对象
        Flyweight flyweight1 = factory.getFlyweight("SharedState");
        Flyweight flyweight2 = factory.getFlyweight("SharedState");
 
        // 使用享元对象
        flyweight1.operate("ExtrinsicState1");
        flyweight2.operate("ExtrinsicState2");
    }
}

运行结果如下:

2、游戏角色

我们举一个形象一些的例子,游戏中需要显示大量的相似的敌人角色,这时就可以使用享元模式复用对象以减少内存开销。

定义角色(抽象享元角色)接口:

public interface GameRole {

    void display(String name);
}

具体角色(具体享元角色)实现:

public class Enemy implements GameRole {

    private String type;

    public Enemy(String type){
        this.type = type;
    }

    @Override
    public void display(String attackType) {
        System.out.println(type+"敌人已启用!"+"攻击方式:"+attackType);
    }
}

角色工厂(享元工厂角色)实现:

import java.util.HashMap;
import java.util.Map;

public class RoleFactory {

  private Map<String, GameRole> pool;

  public RoleFactory() {
    pool = new HashMap<>();
  }

  GameRole getRole(String type) {
    if(!pool.containsKey(type)) {
      pool.put(type, new Enemy(type)); 
    }
    return pool.get(type);
  }
}

客户端:

public class Client {

    public static void main(String[] args) {
        RoleFactory factory = new RoleFactory();
        GameRole a = factory.getRole("A");
        GameRole b = factory.getRole("B");
        a.display("boom");
        b.display("fly");

    }
}

运行结果如下:

五、总结

优点:

1、减少内存占用,降低系统资源消耗。

2、提高系统性能。

缺点:

1、增加了系统的复杂度;

2、区分内部状态和外部状态可能会很复杂;

3、享元模式使得系统难以维护和扩展。

应用场景:

1、一个应用程序使用大量的相似对象。

2、对象的大多数状态都可以外部化。

3、在内存是关键资源的系统中。

4、系统要求消除大量相似类的重复对象。

例如游戏设计中复用相同的角色对象、网站设计的外观样式、多线程池中的线程对象等都适合使用享元模式。

符合的设计原则:

1、单一职责原则(Single Responsibility Principle)

享元模式分离了内部状态和外部状态。

2、开闭原则(Open Close Principle)

新增享元对象不影响其他对象。

3、组合聚合复用原则(Composite Reuse Principle)

享元对象可以被组合、聚合。

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

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

相关文章

【动态规划算法】-简单多状态题型(11-18题)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你…

微信小程序(二)

目录 1、input标签 一、表单绑定 1、数据绑定 2、输入获取 二、网络请求 1、介绍 2、注意 3、使用 4、基于Promise封装 三、自定义组件 1、创建 2、父向子组件通信 3、子向父组件通信 4、生命周期 四、vant weapp组件库 1、配置 2、使用 进入本章前的拓展&#…

宇宙的尽头是银行?聊聊在银行做软件测试的那些事

从一家工作了5年的软件公司的测试管理者跳槽到**银行做软件测试&#xff0c;短短2个月&#xff0c;对银行测试有了初步认识&#xff0c;总结和记录下来&#xff0c;加深个人的理解&#xff0c;同时也共享给各位。 银行作为大家的理财顾问&#xff0c;对金钱非常敏感&#xff0…

118、仿真-基于51单片机的直流电压电流控制系统设计(Proteus仿真+程序等)

方案选择 单片机的选择 方案一&#xff1a;AT89C52是美国ATMEL公司生产的低电压&#xff0c;高性能CMOS型8位单片机&#xff0c;器件采用ATMEL公司的高密度、非易失性存储技术生产&#xff0c;兼容标准MCS-51指令系统&#xff0c;片内置通用8位中央处理器(CPU)和Flash存储单元…

想冲嵌入式,学这套教程

今天&#xff0c;给大家带来一套非常前沿的视频教程&#xff01;有多前沿&#xff1f;诸君&#xff0c;请听我一一道来&#xff1a; 众所周知&#xff0c;现在嵌入式空前火热&#xff0c;随着AI驾驶、智能机器人、智能制造、智慧家居等智能软硬件的飞速发展&#xff0c;嵌入式已…

PLC工作者的工作待遇现状如何?

PLC工作者的工作待遇通常会受到多个因素的影响&#xff0c;包括地理位置、经验水平、行业需求以及个人技能等。 我这里刚好有嵌入式、单片机、plc的资料需要可以私我或在评论区扣个6 在一般情况下&#xff0c;PLC工作者通常拥有较高的技术水平和专业知识&#xff0c;因此他们…

关于自学\跳槽\转行做网络安全行业的一些建议

很好&#xff0c;如果你是被题目吸引过来的&#xff0c;那请看完再走&#xff0c;还是有的~ 为什么写这篇文章 如何自学入行&#xff1f;如何小白跳槽&#xff0c;年纪大了如何转行等类似问题 &#xff0c;发现很多人都有这样的困惑。下面的文字其实是我以前的一个回答&#…

pnpm改造替换npm

Q: 为什么要迁移pnpm&#xff1f; 相比于npm&#xff0c;pnpm有一些优势&#xff1a; 更快的安装速度: 在安装包时&#xff0c;pnpm使用了硬链接的方式&#xff0c;将已安装的包链接到新的目录下&#xff0c;而不是复制或下载包。这样&#xff0c;当你安装一个包的不同版本或者…

LLM - DataCollatorForLanguageModeling 样本生成 by transformers

目录 一.引言 二.生成样本 By API 1.样本处理样式 2.DataCollatorForLanguageModeling 2.1 样本准备 2.2 API 生成 三.生成样本 By DIY 1.样本准备 2.data_colloator 实现 3.使用自定义 data_colloator 四.总结 一.引言 前面我们讲了 Baichuan7B 的 lora 微调步骤&a…

2023年7月广州/惠州/深圳软考信息系统项目管理师报名

信息系统项目管理师是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目之一&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资…

矩阵的范数和特征值之间的关系

参考&#xff1a; linear algebra - Why is the norm of a matrix larger than its eigenvalue? - Mathematics Stack Exchange

SpringBoot 对象存储 MinIO

SpringBoot 对象存储 MinIO 1.MinIO简介 MinIO 是一个基于 Go 实现的高性能、兼容 S3 协议的对象存储。它采用 GNU AGPL v3 开源协议&#xff0c;项目地址是 https://github.com/minio/minio&#xff0c;官网是 https://min.io。 它适合存储海量的非结构化的数据&#xff0c…

园区能源控制管理系统

园区能源控制管理系统是一种能够实现对园区内能源消耗、供应和分配进行实时监控、管理和控制的系统。该系统通过对园区内各种能源设备的数据采集、处理和分析&#xff0c;为管理者提供实时的能源使用情况和数据分析&#xff0c;从而帮助管理者制定科学的能源管理策略和节能措施…

《向量数据库指南》——传统数据库上的向量搜索插件

传统数据库上的向量搜索插件 很好,现在我们已经知道了向量搜索库和向量数据库之间的区别,下面让我们来看看向量数据库与向量搜索插件有何不同。 很多传统关系型数据库和搜索系统,如 ClickHouse 和 Elasticsearch,都包含内置的向量搜索插件。例如,Elasticsearch 8.0 包…

疫情数据微处理——Numpy实战

注&#xff1a;文章内容参考了莫烦python 一、数据来源 数据来自于Kaggle公开免费数据集&#xff0c;需要的伙伴可以自行到这里下载。 二、展示数据 我们用一个字典存储csv数据的第一行、每一行开头的日期以及除了这两者外的数据。 import csv import numpy as npwith ope…

2023年7月13日,Stream流,Stream流的获取,Stream流中间聚合操作,Stream流终结操作,Calendar时间日期类,包装类

Stream流 1. 单列集合的Stream流获取 Java中的Stream流操作可以分为中间操作和终止操作两种。 中间操作包括&#xff1a; filter&#xff1a;对流中的元素进行筛选。map&#xff1a;对流中的元素进行转换。flatMap&#xff1a;对流中的元素进行扁平化映射。distinct&#x…

重启Oracle数据库

root 用户登录服务器。 1、 以oracle身份登录数据库&#xff0c;命令&#xff1a;su - oracle 2、 进入Sqlplus控制台&#xff0c;命令&#xff1a;sqlplus /nolog 3、 以系统管理员登录&#xff0c;命令&#xff1a;connect / as sysdba可以合并为&#xff1a;sqlplus sys/密码…

Acwing:第 111 场周赛(2023.7.12 C++)

目录 5047. 1序列 题目描述&#xff1a; 实现代码&#xff1a; 5048. 无线网络 题目描述&#xff1a; 实现代码&#xff1a; 二分 贪心 5049. 选人 题目描述&#xff1a; 实现代码&#xff1a; 数学 5047. 1序列 题目描述&#xff1a; 实现代码&#xff1a; #incl…

如何实现浏览器内多个标签页之间的通信?

1、使用 LocalStorage 特点&#xff1a;同域共享存储空间&#xff1b;持久化将数据存储在浏览器&#xff1b;提供事件监听storage变化 实现逻辑&#xff1a; A页面将数据存储在本地。B页面监听storage的变化&#xff0c;同步storage的最新数据&#xff1b; 好处&#xff1a;操…

绘制数据图

读取文件&#xff1a; ( 1960 : 30 64 6 ) (1970 : 24 69 7 ) (1980 : 23 68 9 ) (1990 : 18 70 12) (2000 : 15 68 17 ) (2010 : 13 64 23 ) (2020 : 12 60 28) ( 2030 : 11 59 30 ) ( 2040 : 11 56 33 ) 运行代码&#xff1a; //绘制数据图 #include"std_lib_facil…