責任鏈設計模式(單例+多例)

目錄

1. 單例責任鏈

2. 多例責任鏈

核心區別對比

實際應用場景

單例實現

多例實現

初始化

初始化責任鏈

執行測試方法


歡迎關注我的博客!26屆java選手,一起加油💘💦👨?🎓😄😂

最近在學習項目的時候學到了責任鏈的設計模式,覺得很有趣,但對我來說也很有挑戰,寫一篇文章記錄我是如何弄懂這個設計模式和帶著例子的全鏈路解析。

責任鏈模式,責任鏈模式是一種行為設計模式,它允許你將請求沿著處理者鏈進行傳遞,直到有一個處理者能夠處理該請求。在這個具體的代碼中,主要用于構建一個規則處理鏈,不同的規則可以依次處理請求。

單例責任鏈和多例責任鏈的區別主要體現在實例管理方式應用場景上,以下是具體對比:

1. 單例責任鏈

  • 定義:整個責任鏈在系統中全局唯一,所有請求共享同一個鏈實例,鏈中的每個節點(處理者)也通常是單例。
  • 特點
    • 線程安全風險:若責任鏈允許動態修改(如追加節點),需考慮線程安全問題(如使用?ConcurrentHashMap?或加鎖)。
    • 固定結構:鏈結構一旦初始化完成,通常不會改變(除非主動修改)。
    • 資源高效:內存中僅存在一個鏈實例,適合穩定且高頻使用的場景。
  • 示例

    java

    @Service
    public class Rule01TradeRuleFactory {@Resource private RuleLogic101 ruleLogic101;@Resource private RuleLogic102 ruleLogic102;public ILogicLink openLogicLink() {// 單例鏈:全局共享同一個 ruleLogic101 和 ruleLogic102 實例ruleLogic101.appendNext(ruleLogic102); return ruleLogic101;}
    }
    

2. 多例責任鏈

  • 定義:每次使用責任鏈時動態創建新實例,鏈結構和節點可能每次不同。
  • 特點
    • 線程安全:每個鏈實例獨立,無并發問題。
    • 靈活性高:可根據需求動態組合節點(如 A→B→C 或 A→C)。
    • 資源消耗:每次創建新鏈,適合低頻或需要靈活配置的場景。
  • 示例

    java

    @Service
    public class MultiInstanceRuleFactory {@Resource private RuleLogic101 ruleLogic101;@Resource private RuleLogic102 ruleLogic102;public ILogicLink createLink(boolean useNode2) {// 多例鏈:每次返回新的鏈結構RuleLogic101 newNode1 = new RuleLogic101(); if (useNode2) {newNode1.appendNext(new RuleLogic102()); }return newNode1;}
    }
    

核心區別對比

維度單例責任鏈多例責任鏈
實例數量全局唯一每次使用時創建新實例
結構靈活性固定(需手動修改)動態組合(如條件添加節點)
線程安全需額外處理(如加鎖)天然線程安全
適用場景高頻、穩定的請求處理低頻、動態配置的請求處理
資源消耗較高(每次創建新對象)

實際應用場景

  • 單例責任鏈:電商風控規則鏈、支付流程校驗鏈(規則固定且高頻調用)。
  • 多例責任鏈:動態任務編排、個性化業務流程(如用戶自定義審批流)。

單例實現

ILogicChainArmory<T, D, R>:該接口定義了責任鏈的基本操作,即獲取下一個處理者(next())和追加下一個處理者(appendNext())。這樣的設計使得責任鏈中的每個處理者都可以動態地連接其他處理者,形成一個鏈式結構。

ILogicLink<T, D, R>:繼承自?ILogicChainArmory<T, D, R>,并額外定義了?apply?方法,用于處理請求。apply?方法接收請求參數?requestParameter?和動態上下文?dynamicContext,并返回處理結果。

AbstractLogicLink<T, D, R>:實現了?ILogicLink<T, D, R>?接口,提供了?next?屬性和?next()appendNext()?方法的基本實現。同時,還提供了一個受保護的?next?方法,用于調用下一個處理者的?apply?方法,從而實現請求的傳遞。

public interface ILogicChainArmory<T, D, R> {ILogicLink<T, D, R> next();ILogicLink<T, D, R> appendNext(ILogicLink<T, D, R> next);}public interface ILogicLink<T, D, R> extends ILogicChainArmory<T, D, R> {R apply(T requestParameter, D dynamicContext) throws Exception;}public abstract class AbstractLogicLink<T, D, R> implements ILogicLink<T, D, R> {private ILogicLink<T, D, R> next;@Overridepublic ILogicLink<T, D, R> next() {return next;}@Overridepublic ILogicLink<T, D, R> appendNext(ILogicLink<T, D, R> next) {this.next = next;return next;}protected R next(T requestParameter, D dynamicContext) throws Exception {return next.apply(requestParameter, dynamicContext);}}

具體實現:

定義兩個實現:

@Slf4j
@Service
public class RuleLogic101 extends AbstractLogicLink<String, Rule02TradeRuleFactory.DynamicContext, String>{@Overridepublic String apply(String requestParameter, Rule01TradeRuleFactory.DynamicContext dynamicContext) throws Exception {log.info("link model01 RuleLogic101");return next(requestParameter, dynamicContext);}}@Slf4j
@Service
public class RuleLogic102 extends AbstractLogicLink<String, Rule02TradeRuleFactory.DynamicContext, String>{@Overridepublic String apply(String requestParameter, Rule01TradeRuleFactory.DynamicContext dynamicContext) throws Exception {log.info("link model01 RuleLogic102");return "link model01 單實例鏈";}}

Rule01TradeRuleFactory?類是一個工廠類,它的主要作用是創建和組裝責任鏈。在這個責任鏈中,RuleLogic101?和?RuleLogic102?是具體的規則處理器,通過工廠類將它們連接成一個鏈,以便按順序處理請求。

@Service
public class Rule01TradeRuleFactory {@Resourceprivate RuleLogic101 ruleLogic101;@Resourceprivate RuleLogic102 ruleLogic102;public ILogicLink<String, Rule02TradeRuleFactory.DynamicContext, String> openLogicLink() {ruleLogic101.appendNext(ruleLogic102);return ruleLogic101;}@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic static class DynamicContext {private String age;}}

測試方法

    @Testpublic void test_model01_01() throws Exception {ILogicLink<String, Rule02TradeRuleFactory.DynamicContext, String> logicLink = rule01TradeRuleFactory.openLogicLink();String logic = logicLink.apply("123", new Rule02TradeRuleFactory.DynamicContext());log.info("測試結果:{}", JSON.toJSONString(logic));}

執行openLogicLink方法

在執行appenNext的時候進行責任鏈的組裝:RuleLogic101->RuleLogic102,并返回

然后就能執行責任鏈頭節點的apply方法,這里return next()就是在AbstractLogicLink里的

protected R next(T requestParameter, D dynamicContext) throws Exception {return next.apply(requestParameter, dynamicContext);}

也就是去執行了RuleLogic102的apply方法:

到此單例的責任鏈就結束

多例實現


鏈表接口:

public interface ILink<E> {boolean add(E e);boolean addFirst(E e);boolean addLast(E e);boolean remove(Object o);E get(int index);void printLinkList();}

鏈表實現

/*** @description 雙向鏈表基礎實現類(責任鏈的底層數據結構)* @param <E> 鏈表存儲的元素類型(這里為 ILogicHandler 實現類)*/
public class LinkedList<E> implements ILink<E> {/** 鏈表名稱(用于標識不同責任鏈) */private final String name;/** 鏈表元素數量(transient 表示序列化時忽略該字段) */transient int size = 0;/** 頭節點引用 */transient Node<E> first;/** 尾節點引用 */transient Node<E> last;/*** 構造函數* @param name 鏈表名稱*/public LinkedList(String name) {this.name = name;}// ============================ 節點操作方法 ============================/*** 在鏈表頭部插入新節點* @param e 待插入的元素*/private void linkFirst(E e) {final Node<E> oldFirst = first; // 保存原頭節點final Node<E> newNode = new Node<>(null, e, oldFirst); // 創建新節點,前驅為 null,后繼為原頭節點first = newNode; // 更新頭節點為新節點// 若原頭節點為空(鏈表為空)if (oldFirst == null) {last = newNode; // 同時更新尾節點} else {oldFirst.prev = newNode; // 原頭節點的前驅指向新節點}size++; // 元素數量加 1}/*** 在鏈表尾部插入新節點* @param e 待插入的元素*/private void linkLast(E e) {final Node<E> oldLast = last; // 保存原尾節點final Node<E> newNode = new Node<>(oldLast, e, null); // 創建新節點,前驅為原尾節點,后繼為 nulllast = newNode; // 更新尾節點為新節點// 若原尾節點為空(鏈表為空)if (oldLast == null) {first = newNode; // 同時更新頭節點} else {oldLast.next = newNode; // 原尾節點的后繼指向新節點}size++; // 元素數量加 1}// ============================ ILink 接口實現 ============================/*** 默認將元素添加到鏈表尾部(接口方法)* @param e 待添加的元素* @return 添加成功返回 true*/@Overridepublic boolean add(E e) {linkLast(e); // 調用尾部插入方法return true;}/*** 在鏈表頭部添加元素(接口方法)* @param e 待添加的元素* @return 添加成功返回 true*/@Overridepublic boolean addFirst(E e) {linkFirst(e); // 調用頭部插入方法return true;}/*** 在鏈表尾部添加元素(接口方法)* @param e 待添加的元素* @return 添加成功返回 true*/@Overridepublic boolean addLast(E e) {linkLast(e); // 調用尾部插入方法return true;}/*** 根據元素值刪除節點(接口方法)* @param o 待刪除的元素值* @return 刪除成功返回 true*/@Overridepublic boolean remove(Object o) {// 處理 null 值的情況if (o == null) {for (Node<E> x = first; x != null; x = x.next) {if (x.item == null) { // 找到值為 null 的節點unlink(x); // 刪除該節點return true;}}} else {// 處理非 null 值的情況for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item)) { // 找到值匹配的節點unlink(x); // 刪除該節點return true;}}}return false; // 未找到匹配節點}/*** 內部刪除節點的方法* @param x 待刪除的節點* @return 被刪除節點的元素值*/private E unlink(Node<E> x) {final E element = x.item; // 保存節點值final Node<E> nextNode = x.next; // 保存后繼節點final Node<E> prevNode = x.prev; // 保存前驅節點// 更新前驅節點的后繼指針if (prevNode == null) {first = nextNode; // 若無前驅,刪除的是頭節點,更新頭節點} else {prevNode.next = nextNode; // 前驅節點的后繼指向后繼節點x.prev = null; // 斷開當前節點的前驅}// 更新后繼節點的前驅指針if (nextNode == null) {last = prevNode; // 若無比后繼,刪除的是尾節點,更新尾節點} else {nextNode.prev = prevNode; // 后繼節點的前驅指向前驅節點x.next = null; // 斷開當前節點的后繼}x.item = null; // 幫助垃圾回收size--; // 元素數量減 1return element; // 返回被刪除的元素值}/*** 根據索引獲取元素(接口方法)* @param index 元素索引* @return 對應位置的元素*/@Overridepublic E get(int index) {return node(index).item; // 先找到節點,再返回其值}/*** 根據索引查找節點(優化查找方向)* @param index 節點索引* @return 對應的節點*/Node<E> node(int index) {// 如果索引在前半部分,從頭部開始查找if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++) {x = x.next; // 向后移動指針}return x;} else {// 如果索引在后半部分,從尾部開始查找Node<E> x = last;for (int i = size - 1; i > index; i--) {x = x.prev; // 向前移動指針}return x;}}// ============================ 輔助方法 ============================/*** 打印鏈表結構(調試用)*/public void printLinkList() {if (size == 0) {System.out.println("鏈表為空");return;}Node<E> temp = first;System.out.printf("鏈表名稱:%s,頭節點:%s,尾節點:%s,整體:", name, first.item, last.item);while (temp != null) {System.out.print(temp.item + " → ");temp = temp.next;}System.out.println("null");}// ============================ 內部節點類 ============================/*** 鏈表節點結構(靜態內部類)* @param <E> 節點存儲的元素類型*/protected static class Node<E> {E item;        // 節點存儲的值Node<E> next;  // 后繼節點引用Node<E> prev;  // 前驅節點引用/*** 節點構造函數* @param prev 前驅節點* @param element 存儲的值* @param next 后繼節點*/public Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}}// ============================ Getter 方法 ============================/*** 獲取鏈表名稱* @return 鏈表名稱*/public String getName() {return name;}
}

業務鏈路BusinessLinkedList

public class BusinessLinkedList<T, D, R> extends LinkedList<ILogicHandler<T, D, R>> implements ILogicHandler<T, D, R>{public BusinessLinkedList(String name) {super(name);}@Overridepublic R apply(T requestParameter, D dynamicContext) throws Exception {Node<ILogicHandler<T, D, R>> current = this.first;do {ILogicHandler<T, D, R> item = current.item;R apply = item.apply(requestParameter, dynamicContext);if (null != apply) return apply;current = current.next;} while (null != current);return null;}}

業務鏈路ILogicHandler

public interface ILogicHandler<T, D, R> {default R next(T requestParameter, D dynamicContext) {return null;}R apply(T requestParameter, D dynamicContext) throws Exception;}

?鏈路裝配:

public class LinkArmory<T, D, R> {private final BusinessLinkedList<T, D, R> logicLink;@SafeVarargspublic LinkArmory(String linkName, ILogicHandler<T, D, R>... logicHandlers) {logicLink = new BusinessLinkedList<>(linkName);for (ILogicHandler<T, D, R> logicHandler: logicHandlers){logicLink.add(logicHandler);}}public BusinessLinkedList<T, D, R> getLogicLink() {return logicLink;}}

初始化

首先有一個責任鏈工廠:

demo01是假設有兩個節點的責任鏈,demo2是假設只有一個節點的責任鏈,

@Service
public class Rule02TradeRuleFactory {@Bean("demo01")public BusinessLinkedList<String, DynamicContext, XxxResponse> demo01(RuleLogic201 ruleLogic201, RuleLogic202 ruleLogic202) {LinkArmory<String, DynamicContext, XxxResponse> linkArmory = new LinkArmory<>("demo01", ruleLogic201, ruleLogic202);return linkArmory.getLogicLink();}@Bean("demo02")public BusinessLinkedList<String, DynamicContext, XxxResponse> demo02(RuleLogic202 ruleLogic202) {LinkArmory<String, DynamicContext, XxxResponse> linkArmory = new LinkArmory<>("demo02", ruleLogic202);return linkArmory.getLogicLink();}@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic static class DynamicContext {private String age;}}//在這里接受上面@Bean注解的注入,并且完成裝配鏈表的工作
public class LinkArmory<T, D, R> {private final BusinessLinkedList<T, D, R> logicLink;@SafeVarargspublic LinkArmory(String linkName, ILogicHandler<T, D, R>... logicHandlers) {logicLink = new BusinessLinkedList<>(linkName);for (ILogicHandler<T, D, R> logicHandler: logicHandlers){logicLink.add(logicHandler);}}public BusinessLinkedList<T, D, R> getLogicLink() {return logicLink;}}

測試方法:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Link02Test {@Resource(name = "demo01")private BusinessLinkedList<String, Rule02TradeRuleFactory.DynamicContext, XxxResponse> businessLinkedList01;@Resource(name = "demo02")private BusinessLinkedList<String, Rule02TradeRuleFactory.DynamicContext, XxxResponse> businessLinkedList02;@Testpublic void test_model02_01() throws Exception {XxxResponse apply = businessLinkedList01.apply("123", new Rule02TradeRuleFactory.DynamicContext());log.info("測試結果:{}", JSON.toJSONString(apply));}@Testpublic void test_model02_02() throws Exception {XxxResponse apply = businessLinkedList02.apply("123", new Rule02TradeRuleFactory.DynamicContext());log.info("測試結果:{}", JSON.toJSONString(apply));}}

執行流程:兩只節點的情況:

初始化責任鏈

在工廠里裝配demo01的兩個節點,

 @Bean("demo01")public BusinessLinkedList<String, DynamicContext, XxxResponse> demo01(RuleLogic201 ruleLogic201, RuleLogic202 ruleLogic202) {LinkArmory<String, DynamicContext, XxxResponse> linkArmory = new LinkArmory<>("demo01", ruleLogic201, ruleLogic202);return linkArmory.getLogicLink();}

進入LinkArmory的構造方法:遍歷節點并添加:

執行linkArmory.getLogicLink(); 獲取這個責任鏈:

執行測試方法

從這里獲取注入的bean,獲取到責任鏈

@Resource(name = "demo01")private BusinessLinkedList<String, Rule02TradeRuleFactory.DynamicContext, XxxResponse> businessLinkedList01;@Testpublic void test_model02_01() throws Exception {XxxResponse apply = businessLinkedList01.apply("123", new Rule02TradeRuleFactory.DynamicContext());log.info("測試結果:{}", JSON.toJSONString(apply));}

執行BusinessLinkedListz中的apply方法,就是遍歷責任鏈,挨個執行apply方法,直到執行到最后有返回值的時候就停止:

然后會執行各個節點的apply方法,并且去往下一個節點

在ILogicHandler的next是直接返回null的,然后再經過判斷:

default R next(T requestParameter, D dynamicContext) {return null;}

返回的是null就會繼續遍歷下一個節點:如果不是null就會結束,并把返回值返回。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/75424.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75424.shtml
英文地址,請注明出處:http://en.pswp.cn/web/75424.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springboot 處理編碼的格式為opus的音頻數據解決方案【java8】

opus編碼的格式概念&#xff1a; Opus是一個有損聲音編碼的格式&#xff0c;由Xiph.Org基金會開發&#xff0c;之后由IETF&#xff08;互聯網工程任務組&#xff09;進行標準化&#xff0c;目標是希望用單一格式包含聲音和語音&#xff0c;取代Speex和Vorbis&#xff0c;且適用…

vue項目引入tailwindcss

vue3項目引入tailwindcss vue3 vite tailwindcss3 版本 初始化項目 npm create vitelatest --template vue cd vue npm install npm run dev安裝tailwindcss3 和 postcss 引入 npm install -D tailwindcss3 postcss autoprefixer // 初始化引用 npx tailwindcss init -p…

Google ADK(Agent Development Kit)簡要示例說明

一、環境準備與依賴安裝 1.1 系統 硬件&#xff1a; GPU NVIDIA 3070加速模型推理&#xff0c;內存64GB軟件&#xff1a; Python 3.11Docker 28.04&#xff08;用于容器化部署&#xff09;Kubernetes 1.25&#xff08;可選&#xff0c;用于集群管理&#xff09; 1.2 安裝 A…

批量給文件編排序號,支持數字序號及時間日期序號編排文件

當我們需要對文件進行編號的時候&#xff0c;我們可以通過這個工具來幫我們完成&#xff0c;它可以支持從 001 到 100 甚至更多的數字序號編號。也可以支持按照日期、時間等方式對文件進行編號操作。這是一種操作簡單&#xff0c;處理起來也非常的高效文件編排序號的方法。 工作…

【系統架構】AI時代下,系統架構師如何修煉

在AI時代,系統架構師的角色正經歷深刻變革,需在技術深度、工具應用與思維模式上全面升級。以下結合行業趨勢與實踐建議,總結系統架構師的修煉路徑: 一、掌握AI工具,重構工作流 自動化文檔與設計 利用生成式AI(如DeepSeek、ChatGPT)完成70%的需求文檔、接口設計及架構圖生…

圖像顏色空間對比(Opencv)

1. 顏色轉換 import cv2 import matplotlib.pyplot as plotimg cv2.imread("tmp.jpg") img_r cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_g cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_h cv2.cvtColor(img, cv2.COLOR_BGR2HSV) img_l cv2.cvtColor(img, cv2.C…

JDBC驅動autosave缺陷的修復與配置指南

opengauss-jdbc-6.0.0.jar和opengauss-jdbc-6.0.0-og.jar版本修復了&#xff1a;autosavealways時&#xff0c;事務嵌套太深&#xff0c;導致棧溢出問題。如果使用的版本低于opengauss-jdbc-6.0.0版本&#xff0c;需要通過替換jdbc驅動和修改url參數來解決autosave缺陷。以下是…

K8S-證書過期更新

K8S證書過期問題 K8S證書過期處理方法 Unable to connect to the server: x509: certificate has expired or is not yet valid 1、查看證書有效期&#xff1a; # kubeadm certs check-expiration2、備份證書 # cp -rp /etc/kubernetes /etc/kubernetes.bak3、直接重建證書 …

2025 年網絡安全終極指南

我們生活在一個科技已成為日常生活不可分割的一部分的時代。對數字世界的依賴性日益增強的也帶來了更大的網絡風險。 網絡安全并不是IT專家的專屬特權&#xff0c;而是所有用戶的共同責任。通過簡單的行動&#xff0c;我們可以保護我們的數據、隱私和財務&#xff0c;降低成為…

Python的那些事第四十九篇:基于Python的智能客服系統設計與實現

基于Python的智能客服系統設計與實現 摘要 隨著人工智能技術的飛速發展,智能客服系統逐漸成為企業提升客戶服務質量和效率的關鍵工具。本文詳細介紹了基于Python的智能客服系統的設計與實現方案,涵蓋了系統架構、核心功能、技術選型及優化建議,旨在為企業構建高效、智能的客…

第Y1周:調用YOLOv5官方權重進行檢測

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 文章目錄 1、前言2、下載源碼3、運行代碼 1、前言 YOLOv5分為YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x四個版本&#xff0c;這里以YOLOv5s為例。 2、下載源碼 安…

Python小程序 - 文件處理3:正則表達式

正則表達式&#xff1a;文本年鑒表。遺留的問題很多。。。用AI再想想 需求&#xff1a;讀入txt文件&#xff0c;過濾文件有關年記錄 0&#xff09;讀入txt文件 1&#xff09;以“。”&#xff0c;中文句號&#xff0c;為界區分一句&#xff0c;最小統計單位 2&#xff09;年格…

【antd + vue】Tree 樹形控件:默認展開所有樹節點 、點擊文字可以“選中/取消選中”節點

一、defaultExpandAll 默認展開所有樹節點 1、需求&#xff1a;默認展開所有樹節點 2、問題&#xff1a; v-if"data.length"判斷的層級不夠&#xff0c;只判斷到了物理那一層&#xff0c;所以只展開到那一層。 3、原因分析&#xff1a; 默認展開所有樹節點, 如果是…

Notepad++安裝Markdown實時預覽插件

具體操作 打開notepad -> 插件 -> 插件管理 -> 可用 -> “Markdown Panel” -> 安裝&#xff0c;安裝完成后工具欄點擊"Markdown Panel"按鈕。 注意&#xff1a;由于網絡等原因可能安裝失敗 導致工具欄沒出現""Markdown Panel"按鈕&am…

OpenHarmony如何編譯安裝系統應用(以settings設置為例)

開發環境 1.OpenHarmony 2.DevEco Studio 3 .Full Sdk 實現步驟 1.獲取設置應用源碼 https://gitee.com/openharmony/applications_settings/tree/OpenHarmony-v5.0.0-Release/ 2,使用 DevEco Studio 和 Full SDK對系統應用進行簽名,默認工程是未配置簽名的狀態,所構建…

【ESP32-microros(vscode-Platformio)】

一、步驟 1、目前支持ESP32 2、同一個局域網 3、上位機要安裝代理&#xff08;電腦或者linux設備&#xff09; 4、可直接通過USB下載&#xff0c;也可以使用官方燒錄工具&#xff0c;具體的分區表地址要從USB燒錄的時候日志查看&#xff0c;一共四個文件&#xff0c;第三個…

.NET MAUI教程2-利用.NET CommunityToolkit.Maui框架彈Toast

在上一篇博文的基礎上繼續操作&#xff1a; .NET MAUI教程1-入門并發布apk包安裝到真機-CSDN博客 本文內容參考&#xff1a; Toast - .NET MAUI Community Toolkit - Community Toolkits for .NET | Microsoft Learn 1 在NuGet包管理器中安裝 MAUI Community Toolkit&…

軟件工程(應試版)圖形工具總結(二)

遇到的問題,都有解決方案,希望我的博客能為你提供一點幫助。 教材參考《軟件工程導論(第六版)》 七、 層次圖(H圖)與HIPO圖 1、概述 1.1、層次圖(Hierarchy Chart / H圖) ?核心定義 ?目的:描述軟件系統的層次結構,體現模塊的從屬關系。?適用階段:自頂向下設計…

java基礎 流(Stream)

Stream Stream 的核心概念核心特點 Stream 的操作分類中間操作&#xff08;Intermediate Operations&#xff09;終止操作&#xff08;Terminal Operations&#xff09; Stream 的流分類順序流&#xff08;Sequential Stream&#xff09;并行流&#xff08;Parallel Stream&…

EAL4+ vs EAL7:高安全場景下的等級選擇策略

在數字化浪潮席卷全球的當下&#xff0c;信息安全已然成為各行各業穩健發展的基石。特別是在高安全需求場景中&#xff0c;選擇契合的安全等級成為保障信息資產安全的關鍵。EAL&#xff08;Evaluation Assurance Level&#xff09;評估保障級作為衡量信息技術產品安全保障能力的…