【设计模式】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 stack
  SET_HEALTH(2),      // e.g. "SET_HEALTH", pop health and wizard number, call set health
  SET_WISDOM(3),      // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
  SET_AGILITY(4),     // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
  PLAY_SOUND(5),      // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
  SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
  GET_HEALTH(7),      // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
  GET_AGILITY(8),     // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
  GET_WISDOM(9),      // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
  ADD(10),            // e.g. "ADD", pop 2 values, push their sum
  DIVIDE(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 stack
          stack.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 

🔍适用场景


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

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

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

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

相关文章

git push后一直卡在在Writing objects:问题

git push后一直卡在Writing objects: 解决&#xff1a;设置 git config --global http.postBuffer 5242880000在执行git push。 一般设置后就可以成功了&#xff0c;后面不用看。 2. 我这里结果又报错&#xff1a; fatal: protocol error: bad line length 8192 MiB | 107.46 …

【C++】d1

关键字&#xff1a; 运行、前缀、输入输出、换行 运行f10 前缀必须项&#xff1a; #include <iostream> using namespace std; 输入/输出&#xff1a; cin >> 输入 cout << 输出 语句通过>>或<<分开 换行 endl或者"\n"

想当安卓开发工程师?学习路线分享!

安卓开发学习路线 在前几篇文章中,对安卓开发岗位的岗位要求做了一些科普,本节文章将介绍安卓开发岗位的学习路线。 目前,网络上有很多面经、算法题解、算法课等学习资料,如何合理利用这些资料成为技术求职者的一大困惑。笔者整理了一份安卓开发岗位学习路线供大家参考,…

第四课 communcation服务-can配置第二弹

Davinci配置目标: 介绍DBC基本属性,并且配置出一个DBC。 将DBC导入到vector的davinci工具,生成我们想要的代码。 Davinci配置步骤: 1. 编辑DBC文件 DBC文件是一种非常重要的工具,所谓DBC就是Database CAN,CAN网络的数据库文件,定义了CAN网络的节点、消息、信号的所有…

网络安全知识核心20要点

1、什么是SQL注入攻击 概述 攻击者在 HTTP 请求中注入恶意的 SQL 代码&#xff0c;服务器使用参数构建数据库 SQL 命令时&#xff0c;恶意SQL 被一起构造&#xff0c;并在数据库中执行。 注入方法 用户登录&#xff0c;输入用户名 lianggzone&#xff0c;密码‘ or ‘1’’…

axios如何传递数组作为参数,后端又如何接收呢????

前端的参数是一个数组。 前端编写&#xff1a; 后端接收&#xff1a;

git解决版本冲突 -git pull

当在Git中遇到版本冲突时&#xff0c;通常是因为两个或更多的开发者在同一时间修改了同一个文件的相同部分&#xff0c;并将这些修改推送到远程仓库。Git无法自动合并这些修改&#xff0c;因此会产生冲突。以下是解决Git版本冲突的基本步骤&#xff1a; 拉取最新代码&#xff…

mybatis-plus 优雅的写service接口中方法(3)

多表联查 上文讲过了自定义sql &#xff0c;和wrapper的使用&#xff0c;但是我们可以发现 我们查询的都是数据库中的一张表&#xff0c;那么怎么进行多表联查呢&#xff0c;当然也是用自定义sql来进行实现 比如说 查询 id 为 1 2 4 的用户 并且 地址在北京 的 用户名称 普…

AI崛起,掌握它,开启智能新生活!

AI崛起&#xff0c;掌握它&#xff0c;开启智能新生活&#xff01; &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &…

LDAP: error code 32 - No Such Object

目前我的项目版本&#xff1a; Spring版本:5.3.15SpringBoot版本:2.6.3 完整错误 org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - No Such Object]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Objec…

Java进阶学习笔记9——子类中访问其他成员遵循就近原则

正确访问成员的方法。 在子类方法中访问其他成员&#xff08;成员变量、成员方法&#xff09;&#xff0c;是依照就近原则的。 F类&#xff1a; package cn.ensource.d13_extends_visit;public class F {String name "父类名字";public void print() {System.out.p…

[算法][前缀和] [leetcode]724. 寻找数组的中心下标

题目地址 https://leetcode.cn/problems/find-pivot-index/description/ 题目描述 代码 class Solution {public int pivotIndex(int[] nums) {int total Arrays.stream(nums).sum();//前缀和int prefixSum 0;int len nums.length;for(int i 0;i<len;i){if (i-1>0){p…

【已解决】C#设置Halcon显示区域Region的颜色

前言 在开发过程中&#xff0c;突然发现我需要显示的筛选区域的颜色是白色的&#xff0c;如下图示&#xff0c;这对我们来说不明显会导致我的二值化筛选的时候存在误差&#xff0c;因此我们需要更换成红色显示这样的话就可以更加的明显&#xff0c;二值化筛选更加的准确。 解…

若依 Ruoyi-Vue PageHelper 分页失效 total为记录数

分页插件PageHelper返回记录总数total竟然出错了 执行控制台的SQL&#xff0c;查询出来的total数量是对的&#xff0c;很奇怪分页的total设置为查询到的记录数。 怀疑对list.stream操作&#xff0c;影响了分页&#xff0c;代码发现确实是这样&#xff0c;debug&#xff0c;居然…

【Mac】跑猫RunCat for mac(菜单栏Cpu可视化监测工具) v10.3免费版安装教程

软件介绍 RunCat是一款为菜单栏提供关键帧动画的软件。动画速度会根据Mac的CPU使用情况而变化。奔跑的小猫通过运行速度告诉您Mac的CPU使用率。 这是一款好玩的软件&#xff0c;可以为您的Mac使用添加一点小确幸。感兴趣的朋友可以试试哦。 安装步骤 1.打开安装包&#xff0…

idea 出现 cpu占用100%

一、IDEA的CPU占用率过高 二、解决办法 idea安装路径bin目录 修改idea64.exe.vmoptions配置文件 原来的 -Xms128m -Xmx750m -XX:ReservedCodeCacheSize240m -XX:UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB50 修改为(IDEA优化内存配置) -Xms2048m -Xmx4096m -XX:Reser…

SpringCloudAlibaba:6.3SpringBoot接入RocketMQ

依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 htt…

C++入门:从C语言到C++的过渡(2)

目录 1.缺省参数 1.1缺省参数的概念 1.2缺省参数的分类及使用 1.3注意点 2.函数重载 2.1函数重载的定义 2.2函数重载的情况分类 2.3注意 2.4函数名修饰规则 3.引用 3.1引用的概念 3.2注意事项 3.3常引用 4.4引用的使用场景 4.4.1作为函数的参数 4.4.2做函数返回…

等保三级 腾讯云控制台检查项设置

1、地址限制 2、角色里加三权用户&#xff08;查看日志权限&#xff09; 3、登录失败处理和超时退出 4、密码复杂度和口令有效期 5、双因素验证 6、操作审计