【設計模式】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.pswp.cn/bicheng/15639.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15639.shtml
英文地址,請注明出處:http://en.pswp.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