【设计模式】JAVA Design Patterns——Bytecode(字节码模式)

🔍目的


允许编码行为作为虚拟机的指令

🔍解释


真实世界例子

一个团队正在开发一款新的巫师对战游戏。巫师的行为需要经过精心的调整和上百次的游玩测试。每次当游戏设计师想改变巫师行为时都让程序员去修改代码这是不妥的,所以巫师行为以数据驱动的虚拟机方式实现。

通俗描述

字节码模式支持由数据而不是代码驱动的行为。

维基百科

指令集定义了可以执行的低级操作。一系列指令被编码为字节序列。虚拟机一次一条地执行这些指令,中间的值用栈处理。通过组合指令,可以定义复杂的高级行为。

程序示例

创建游戏对象 巫师

@AllArgsConstructor
@Setter
@Getter
@Slf4j
public class Wizard {private int health;private int agility;private int wisdom;private int numberOfPlayedSounds;private int numberOfSpawnedParticles;public void playSound() {LOGGER.info("Playing sound");numberOfPlayedSounds++;}public void spawnParticles() {LOGGER.info("Spawning particles");numberOfSpawnedParticles++;}
}

 展示虚拟机可用的指令。每个指令对于如何操作栈中的数据都有自己的语义。例如,增加指令,其取得栈顶的两个元素并把结果压入栈中。

@AllArgsConstructor
@Getter
public enum Instruction {LITERAL(1),         // e.g. "LITERAL 0", push 0 to stackSET_HEALTH(2),      // e.g. "SET_HEALTH", pop health and wizard number, call set healthSET_WISDOM(3),      // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdomSET_AGILITY(4),     // e.g. "SET_AGILITY", pop agility and wizard number, call set agilityPLAY_SOUND(5),      // e.g. "PLAY_SOUND", pop value as wizard number, call play soundSPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particlesGET_HEALTH(7),      // e.g. "GET_HEALTH", pop value as wizard number, push wizard's healthGET_AGILITY(8),     // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agilityGET_WISDOM(9),      // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdomADD(10),            // e.g. "ADD", pop 2 values, push their sumDIVIDE(11);         // e.g. "DIVIDE", pop 2 values, push their division// ...
}

创建核心类  虚拟机 类 。 它将指令作为输入并执行它们以提供游戏对象行为。

@Getter
@Slf4j
public class VirtualMachine {private final Stack<Integer> stack = new Stack<>();private final Wizard[] wizards = new Wizard[2];public VirtualMachine() {wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),0, 0);wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),0, 0);}public VirtualMachine(Wizard wizard1, Wizard wizard2) {wizards[0] = wizard1;wizards[1] = wizard2;}public void execute(int[] bytecode) {for (var i = 0; i < bytecode.length; i++) {Instruction instruction = Instruction.getInstruction(bytecode[i]);switch (instruction) {case LITERAL:// Read the next byte from the bytecode.int value = bytecode[++i];// Push the next value to stackstack.push(value);break;case SET_AGILITY:var amount = stack.pop();var wizard = stack.pop();setAgility(wizard, amount);break;case SET_WISDOM:amount = stack.pop();wizard = stack.pop();setWisdom(wizard, amount);break;case SET_HEALTH:amount = stack.pop();wizard = stack.pop();setHealth(wizard, amount);break;case GET_HEALTH:wizard = stack.pop();stack.push(getHealth(wizard));break;case GET_AGILITY:wizard = stack.pop();stack.push(getAgility(wizard));break;case GET_WISDOM:wizard = stack.pop();stack.push(getWisdom(wizard));break;case ADD:var a = stack.pop();var b = stack.pop();stack.push(a + b);break;case DIVIDE:a = stack.pop();b = stack.pop();stack.push(b / a);break;case PLAY_SOUND:wizard = stack.pop();getWizards()[wizard].playSound();break;case SPAWN_PARTICLES:wizard = stack.pop();getWizards()[wizard].spawnParticles();break;default:throw new IllegalArgumentException("Invalid instruction value");}LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());}}public void setHealth(int wizard, int amount) {wizards[wizard].setHealth(amount);}// other setters ->// ...
}

展示虚拟机完整示例

 

  public static void main(String[] args) {var vm = new VirtualMachine(new Wizard(45, 7, 11, 0, 0),new Wizard(36, 18, 8, 0, 0));vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH"));vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY"));vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM"));vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2"));vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE"));vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH"));}

控制台输出

 

16:20:10.193 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0]
16:20:10.196 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 0]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_HEALTH, Stack contains [0, 45]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 0]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_AGILITY, Stack contains [0, 45, 7]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 7, 0]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_WISDOM, Stack contains [0, 45, 7, 11]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 45, 18]
16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 18, 2]
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed DIVIDE, Stack contains [0, 45, 9]
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 54]
16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed SET_HEALTH, Stack contains []

🔍类图


Bytecode class diagram 

🔍适用场景


当您需要定义很多行为并且游戏的实现语言不合适时,请使用字节码模式,因为:

  • 它的等级太低,使得编程变得乏味或容易出错。
  • 由于编译时间慢或其他工具问题,迭代它需要很长时间。
  • 它有太多的信任。 如果您想确保定义的行为不会破坏游戏,您需要将其与代码库的其余部分进行沙箱化。

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

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

相关文章

环形链表Ⅱ-力扣

第一种解法时哈希表&#xff0c;set在使用insert插入时&#xff0c;会返回一个pair&#xff0c;如果pair的值为0&#xff0c;则插入失败&#xff0c;那么返回这个插入失败的节点&#xff0c;就是入环的第一个节点&#xff0c;代码如下&#xff1a; /*** Definition for singly…

导航【面试准备】

导航【面试准备】 前言版权导航【面试准备】面经准备 最后 前言 2024-5-20 12:47:11 以下内容源自《【面试准备】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是https://jsss-1.blog.csdn.net 禁止其他平…

AcW木棒-XMUOJ恢复破碎的符咒木牌-DFS与剪枝

题目 思路 话不多说&#xff0c;直接上代码 代码 /* AcW木棒-XMUOJ恢复破碎的符咒木牌 搜索顺序&#xff1a;从小到大枚举最终的长度 len从前往后依次拼每根长度为len的木棍 优化&#xff1a; 1.优化搜索顺序&#xff1a;优先选择深度短的来搜索&#xff0c;故从大到小去枚…

【系统分析师】WEB开发-案例

文章目录 1、WEB开发涉及内容1.1 负载均衡技术1.2 数据库读写分离1.3 缓存 缓解读库压力1.4 CDN1.5 WEB应用服务器1.6 整体结构1.6 相关技术1.6.1 redis相关(集群、持久化等)1.6.2 XML与JSON1.6.3 REST1.6.4 响应式web设计1.6.5 关于中台1.6.6 Web系统分层 1、WEB开发涉及内容 …

Python--面向对象

面向对象⭐⭐ 1. 面向对象和面向过程思想 面向对象和面向过程都是一种编程思想,就是解决问题的思路 面向过程&#xff1a;POP(Procedure Oriented Programming)面向过程语言代表是c语言面向对象&#xff1a;OOP(Object Oriented Programming)常见的面向对象语言包括:java c g…

19c数据库19.9以下dg切换打开hang住问题

原主库发起切换请求&#xff0c;原主库正常切换数据库角色&#xff0c;但原从库无法正常打开数据库&#xff0c;尝试关闭重启&#xff0c;依旧无法解决问题。 查看切换过程中原从库数据库后台日志&#xff0c;发现数据库一直不断重试清理 SRLs&#xff0c; 后台alert日志&…

力扣HOT100 - 21. 合并两个有序链表

解题思路&#xff1a; class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode dum new ListNode(0), cur dum;while (list1 ! null && list2 ! null) {if (list1.val < list2.val) {cur.next list1;list1 list1.next;} els…

基本IO接口

引入 基本输入接口 示例1 示例2&#xff1a;有数据保持能力的外设 #RD端由in指令控制&#xff1a;将数据由端口传输到CPU内存中 #CS244信号由译码电路实现 示例3&#xff1a; a)图中由于输出端口6有连接到端口1&#xff0c;当开关与端点1闭合时期间&#xff0c;仍能维持3端口…

插件:NGUI

一、版本 安装完毕后重启一下即可&#xff0c;否则可能创建的UI元素不生效 二、使用 Label文字 1、创建Canvs 2、只有根节点的这些脚本全部展开才能鼠标右键创建UI元素 3、选择字体 Sprite图片 1、选择图集 2、选择图集中的精灵 Panel容器 用来装UI的容器&#xff0c;一般UI…

设计模式-策略模式-使用

设计模式-策略模式-CSDN博客 系统中有很多类&#xff0c;它们之间的区别仅在于它们的行为。策略模式可以定义一系列的算法&#xff0c;并将它们一个个封装起来&#xff0c;使它们可以相互替换。这样&#xff0c;算法就可以独立于使用它的客户而变化。需要使用算法的不同变体。…

《计算机网络微课堂》2-5 信道的极限容量

本节课我们介绍信道极限容量的有关问题。 我们都知道信号在传输过程中会受到各种因素的影响&#xff0c;如图所示&#xff0c;这是一个数字信号&#xff0c;‍‍当它通过实际的信道后&#xff0c;波形会产生失真&#xff0c;当失真不严重时&#xff0c;在输出端‍‍还可根据以失…

Redis实现热点数据排行榜或游戏积分排行榜

数据库中的某张表中存储着文章的浏览量&#xff0c;或者点赞数等&#xff0c;或者游戏积分等数据...... 这些数据的更新在redis中完成&#xff0c;并定时同步到mysql数据库中。 而如果要对这些数据进行排序的话&#xff1a; Redis中的Sorted Set(有序集合)非常适合用于实现排…

vue源码2

vue之mustache库的机理其实是将模板字符串转化为tokens 然后再将 tokens 转化为 dom字符串&#xff0c;如下图 对于一般的将模板字符串转化为dom字符串&#xff0c;这样不能实现复杂的功能 let data {name:小王,age:18 } let templateStr <h1>我叫{{name}},我今年{{ag…

centos7 服务开机自启动 - systemctl -以禅道为例

在服务器上安装的各种中间件&#xff0c;一般都需要配置成开机自启动。但是有些中间件的安装过程中并没有提供相关配置开机自启动的说明文档。本文总结一下Centos7通过systemctl enble配置服务自启动的方法。一、Centos7通过systemctl enble配置服务自启动 在Centos7后&#x…

GraphSAGE

GraphSAGE 节点采样&#xff1a;聚合&#xff08;Aggregation&#xff09;&#xff1a;更新&#xff08;update&#xff09;&#xff1a;例子&#xff1a;总结&#xff1a; 啥是GraphSAGE呢&#xff1f; 是一种用于图嵌入的无监督学习方法。 通过采样和聚合邻居节点的信息来生成…

【一步一步了解Java系列】:Java中的方法对标C语言中的函数

看到这句话的时候证明&#xff1a;此刻你我都在努力~ 加油陌生人~ 个人主页&#xff1a;Gu Gu Study 专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹。 _ 如果喜欢能否点个赞支持一下&#xff0c;谢谢…

Xfce4桌面背景和桌面图标消失问题解决@FreeBSD

问题&#xff1a;Xfce4桌面背景和桌面图标消失 以前碰到过好几次桌面背景和桌面图标消失&#xff0c;整个桌面除了上面一条和下面中间的工具条&#xff0c;其它地方全是黑色的问题&#xff0c;但是这次重启之后也没有修复&#xff0c;整个桌面乌黑一片&#xff0c;啥都没有&am…

认知V2X的技术列一个学习大纲

为了深入学习和理解V2X&#xff08;Vehicle to Everything&#xff09;技术&#xff0c;以下是一个学习大纲的概述&#xff0c;结合了参考文章中的相关数字和信息&#xff1a; 一、V2X技术基础 V2X概述 定义&#xff1a;V2X是车用无线通信技术&#xff0c;将车辆与一切事物相连…

WebService相关内容

WebService中的wsdl什么意思? WSDL(Web Services Description Language)Web服务描述语言及其功能、操作、参数和返回值的XML格式的语言。它在Java和其他编程语言中都可以使用,用于定义Web服务的接口以及如何与这些服务进行交互。 WSDL的作用 WSDL的主要作用是提供一种标准…

idea上传git命令

git init git remote add origin git add . git commit -m "标题" git push -u origin master