【設計模式】- 行為型模式1

模板方法模式

定義了一個操作中的算法骨架,將算法的一些步驟推遲到子類,使得子類可以不改變該算法結構的情況下重定義該算法的某些步驟

主要角色】:

  • 抽象類:給出一個算法的輪廓和骨架(包括一個模板方法 和 若干基本方法)
    • 模板方法:定義了算法的骨架(執行順序),按某種順序調用其包含的基本方法
    • 基本方法:實現算法各個步驟的方法
      • 抽象方法:由抽象類聲明,具體子類實現
      • 具體方法:由抽象類或具體類聲明或實現,子類可以覆蓋也可以繼承
      • 鉤子方法:在抽象類中已經實現,包含用于判斷的邏輯方法和需要子類重寫的空方法(一般是用于判斷的邏輯方法,方法名為isXxx,返回值為boolean類型)
  • 具體子類:實現抽象類中所定義的抽象方法和鉤子方法

案例:炒菜

需求】:炒菜的步驟是固定的,分為倒油、熱油、倒蔬菜、倒調料品、翻炒等步驟。

抽象類(定義模板方法和基本方法):

public abstract class AbstractClass {// 模板方法定義(子類不能修改模板方法)public final void cookProcess() {pourOil();heatOil();pourVegetable();pourSauce();fry();}public void pourOil() {System.out.println("倒油");}public void heatOil() {System.out.println("熱油");}// 倒蔬菜(一個是包菜、一個是菜心)public abstract void pourVegetable();// 倒調味品public abstract void pourSauce();public void fry() {System.out.println("翻炒");}
}

炒包菜類、炒菜心類(具體子類):

public class ConcreteClassBaoCai extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下鍋的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下鍋的醬料是辣椒");}
}public class ConcreteClassCaiXin extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下鍋的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下鍋的醬料是蒜蓉");}
}

測試類:

public class Client {public static void main(String[] args) {// 創建對象AbstractClass baoCai = new ConcreteClassBaoCai();// 調用炒菜功能baoCai.cookProcess();}
}

將相同的代碼放在抽象的父類中,把不同的代碼放入不同的子類中。

適用場景

  1. 算法的整體部分比較固定,個別部分容易改變,就可以使用模板方法,將容易變化的部分抽象出來,讓子類去實現這些方法。
  2. 通過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制。

策略模式

該模式定義了一系列算法, 使他們可以互相替換,算法的變化不會影響使用算法的客戶。

主要角色】:

  • 抽象策略類:由一個接口或抽象類實現,給出所有具體策略所需的接口
  • 具體策略類:實現了抽象策略類定義的接口,提供具體的算法實現或行為
  • 環境類:持有一個策略類的引用,最終給客戶端調用

案例:促銷活動

需求】:超市爭對不同的節日(春節、中秋節、圣誕節)推出不同的促銷活動,由促銷員(環境類)將促銷活動展示給客戶。

抽象策略類:

public interface Strategy {void show();
}

策略A、B、C類(具體策略類):

public class StrategyA implements Strategy {@Overridepublic void show() {System.out.println("買一送一");}
}public class StrategyB implements Strategy {@Overridepublic void show() {System.out.println("滿200減50");}
}public class StrategyC implements Strategy {@Overridepublic void show() {System.out.println("打8折");}
}

銷售員類(環境類):

public class SalesMan {private Strategy strategy;public SalesMan(Strategy strategy) {this.strategy = strategy;}// 由促銷員展示促銷活動給普通用戶public void salesManShow() {strategy.show();}
}

測試類:

public class Client {public static void main(String[] args) {// 切換策略ASalesMan salesMan = new SalesMan(new StrategyA());salesMan.salesManShow();// 切換策略BsalesMan = new SalesMan(new StrategyB());salesMan.salesManShow();// 切換策略CsalesMan = new SalesMan(new StrategyC());salesMan.salesManShow();}
}

策略類之間可以自由切換;
增加一個新的策略只需要添加一個具體的策略類
策略模式可以避免使用多重的if else 和 switch case

適用場景

  1. 需要動態在幾種算法中選擇一種,可以把每個算法封裝到策略類中
  2. 大量的if else和switch cash完全可以用策略模式代替,讓代碼更加美觀優雅

命令模式

將請求封裝成一個對象,使發出請求的責任和執行請求的責任分隔開,這樣兩者之間通過命令對象進行溝通,方便將命令對象進行存儲、傳遞、調用、增加、管理。

主要角色

  • 抽象命令角色:定義命令的接口,聲明執行方法
  • 具體命令角色:實現命令接口,通常會持有接收者,并調用接收者的功能來完成命令要執行的操作
  • 實現者 / 接收者角色:真正執行命令的對象
  • 調用者 / 請求者角色:要求命令對象執行請求,通常會持有命令對象

案例:點餐

  • 服務員:調用者角色,由服務員發起命令
  • 廚師:接收者命令,真正命令執行的對象
  • 訂單:命令中包含訂單
    在這里插入圖片描述

訂單類:

@Data
public class Order {// 餐桌號碼private int diningTable;// 所下餐品和份數private Map<String, Integer> foodDir = new HashMap<>();// 添加食物public void addFood(String name, int num) {foodDir.put(name, num);}
}

廚師類(接收者):

public class Chef {// 制作食物public void makeFood(String name, int num) {System.out.println(num + "份" + name);}
}

抽象命令類:

public interface Command {void execute();
}

具體命令類:

public class OrderCommand implements Command {// 持有接收者對象private Chef receiver;private Order order;public OrderCommand(Chef receiver, Order order) {this.receiver = receiver;this.order = order;}@Overridepublic void execute() {System.out.println(order.getDiningTable() + "桌的訂單:");Map<String, Integer> foodDir = order.getFoodDir();foodDir.forEach((foodName, num)->{receiver.makeFood(foodName, num); // 讓廚師去完成訂單里的菜品});System.out.println(order.getDiningTable() + "桌的飯準備完畢");}
}

服務員類(調用者角色):

public class Waitor {// 持有多個命令對象private List<Command> commands = new ArrayList<>();public void addCommand(Command command) {// 將command存儲到List集合中commands.add(command);}// 發起命令public void orderUp() {System.out.println("服務員:廚師,訂單來啦");commands.forEach(command -> {if(command != null) command.execute();});}
}

測試類:

public class Client {public static void main(String[] args) {// 創建第一個訂單對象Order order1 = new Order();order1.setDiningTable(1);order1.addFood("西紅柿雞蛋面", 1);order1.addFood("小杯可樂", 2);// 創建第二個訂單對象Order order2 = new Order();order2.setDiningTable(2);order2.addFood("油悶大蝦", 1);order2.addFood("小杯雪碧", 1);// 創建廚師對象Chef receiver = new Chef();// 創建命令對象OrderCommand cmd1 = new OrderCommand(receiver, order1);OrderCommand cmd2 = new OrderCommand(receiver, order2);// 創建調用者Waitor invoke = new Waitor();invoke.addCommand(cmd1);invoke.addCommand(cmd2);// 讓服務員發起命令invoke.orderUp();}
}

適用場景

  1. 系統需要將請求調用這和請求接收者解耦
  2. 系統需要在不同時間指定請求、將請求排隊和執行請求
  3. 系統需要支持命令的撤銷(undo)和恢復(redo)操作

JDK源碼解析:Runnable類

Runnable類就是一個命令模式,Thread是調用者,start()方法就是執行方法

責任鏈模式

避免發送者和多個請求處理者耦合在一起,將所有請求的處理者通過錢一個對象記住其下一個對象的引用而連成一條鏈;當請求發生時,可以將請求沿著這條鏈傳遞,直到有對象處理它為止

問題】公司員工請假,可以批假的領導有:部門負責人、副總經理、總經理,但是每個領導可以批準的天數不同。員工需要根據自己要請假的天數去找不同的領導簽字。
解決】:比如有個員工要請假,他只需要去找部門負責人,如果部門負責人發現他請假的時間自己處理不了,就會把這個請假單交給副總經理,如果副總經理處理不了,就會交給總經理處理。

主要角色】:

  • 抽象處理者角色:定義一個處理請求的接口,包含抽象處理方法和后繼處理方法
  • 具體處理者角色:實現抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理就處理;如果不能處理就把它轉發給后繼的處理者
  • 客戶類角色:創建處理鏈,并向鏈頭的具體處理者對象提交請求,它不關心處理細節和請求的傳遞過程

案例:請假流程

需求】:請假一天以下的只需要小組長同意;請假1-3天需要部門經理同意;請假3-7天需要總經理同意。

請假條類:

@AllArgsConstructor
@Data
public class LeaveRequest {// 姓名private String name;// 請假天數private int num;// 請假內容private String content;
}

抽象處理者類:

@Data
public abstract class Handler {protected final static int NUM_ONE = 1;protected final static int NUM_THREE = 3;protected final static int NUM_SEVEN = 7;// 領導了可以處理的天數區間private int numStart;private int numEnd;public Handler(int numStart, int numEnd) {this.numStart = numStart;this.numEnd = numEnd;}// 聲明后繼者(上級領導)private Handler nextHandler;// 各級領導處理請假條的方法protected abstract void handleLeave(LeaveRequest leave);// 提交請假條(不能被繼承)public final void submit(LeaveRequest leave) {// 該領導審批handleLeave(leave);if(nextHandler != null && leave.getNum() > numEnd) {// 交給上級領導審批nextHandler.handleLeave(leave);} else {System.out.println("流程結束");}}
}

小組長類、部門經理類、總經理類(具體的處理者)

public class GroupLeader extends Handler {public GroupLeader() {super(0, Handler.NUM_ONE);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "請假" + leave.getNum() + "天,原因:" + leave.getContent());System.out.println("小組長審批:同意");}
}public class Manager extends Handler {public Manager() {super(Handler.NUM_ONE, Handler.NUM_THREE);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "請假" + leave.getNum() + "天,原因:" + leave.getContent());System.out.println("部門經理審批:同意");}
}public class GeneralManager extends Handler {public GeneralManager() {super(Handler.NUM_THREE, Handler.NUM_SEVEN);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "請假" + leave.getNum() + "天,原因:" + leave.getContent());System.out.println("總經理類審批:同意");}
}

測試類:

public class Client {public static void main(String[] args) {// 1. 創建請假條對象LeaveRequest leave = new LeaveRequest("小明", 1, "身體不適");// 2. 創建各級領導對象GroupLeader groupLeader = new GroupLeader();Manager manager = new Manager();GeneralManager generalManager = new GeneralManager();// 3. 設置處理者鏈groupLeader.setNextHandler(manager);manager.setNextHandler(generalManager);// 4. 小明提交請假groupLeader.submit(leave); // 調用小組長里的submit()方法}
}

降低了請求發送者 和 請求接收者的耦合度
每個類只需要處理自己該處理的工作,不能處理的傳遞給下一個對象完成

狀態模式

案例引入:電梯

電梯接口:

public interface ILift {// 電梯狀態常量int OPENING_STATE = 1;int CLOSING_STATE = 2;int RUNNING_STATE = 3;int STOPPING_STATE = 4;// 設置電梯狀態void settState(int state);// 電梯操作功能void open(); // 開門void close(); // 關門void run(); // 運行void stop(); // 停止
}

電梯類(ILift的子實現類):

public class Lift implements ILift {// 記錄當前電梯的狀態private int state;@Overridepublic void settState(int state) {this.state = state;}@Overridepublic void open() {if(state == STOPPING_STATE || state == CLOSING_STATE) {System.out.println("電梯打開");settState(OPENING_STATE);}}@Overridepublic void close() {if(state == OPENING_STATE) {System.out.println("電梯關閉");settState(CLOSING_STATE);}}@Overridepublic void run() {if(state == CLOSING_STATE || state == STOPPING_STATE) {System.out.println("電梯運行");settState(RUNNING_STATE);}}@Overridepublic void stop() {if(state == CLOSING_STATE || state == RUNNING_STATE) {System.out.println("電梯停止");settState(STOPPING_STATE);}}
}

測試類:

public class Client {public static void main(String[] args) {// 1. 創建電梯對象Lift lift = new Lift();// 2. 設置電梯狀態lift.settState(ILift.OPENING_STATE);// 3. 操作電梯lift.open();lift.close();lift.run();lift.stop();}
}

存在問題】使用了大量的if else,使得閱讀性變差。而且如果需要新增一個斷電的狀態,也需要修改上邊的代碼邏輯

狀態模式:對于有狀態的對象,把復雜的判斷邏輯提取到不同的狀態對象中,允許狀態對象在內部狀態發生改變時改變其行為。

主要角色

  • 環境角色:定義了客戶程序需要的接口,維護一個當前的狀態,并將與狀態相關的操作委托給當前狀態對象來處理
  • 義一個接口,用來封裝環境對象中特定狀態所對應的行為
  • 具體狀態角色:實現抽象狀態所對應的行為

案例:電梯

抽象狀態類:

@Data
public abstract class LiftState {// 環境角色變量protected Context context;// 電梯開啟public abstract void open();// 電梯關閉public abstract void close();// 電梯運行public abstract void run();// 電梯停止public abstract void stop();
}

環境角色類:

public class Context {// 定義對應狀態的常量public final static OpeningState OPENING_STATE = new OpeningState();public final static ClosingState CLOSING_STATE = new ClosingState();public final static RunningState RUNNING_STATE = new RunningState();public final static StoppingState STOPPING_STATE = new StoppingState();// 定義一個當前狀態變量private LiftState liftState;public LiftState getLiftState() {return liftState;}public void setLiftState(LiftState liftState) {this.liftState = liftState;// 設置當前對象的Context對象this.liftState.setContext(this);}public void open() {this.liftState.open();}public void close() {this.liftState.close();}public void run() {this.liftState.run();}public void stop() {this.liftState.stop();}
}

電梯關閉、開啟、運行、停止狀態類(具體狀態類):

public class ClosingState extends LiftState {@Overridepublic void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.getLiftState().open();}@Overridepublic void close() {System.out.println("電梯關閉");}@Overridepublic void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.getLiftState().run();}@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.getLiftState().stop();}
}public class OpeningState extends LiftState {// 當前狀態要執行的方法@Overridepublic void open() {System.out.println("電梯 開啟");}@Overridepublic void close() {// 修改狀態super.context.setLiftState(Context.CLOSING_STATE);// 調用當前狀態中的close()方法super.context.close();}@Overridepublic void run() {// 什么都不做}@Overridepublic void stop() {// 什么都不做}
}public class RunningState extends LiftState {@Overridepublic void open() {// 什么都不做}@Overridepublic void close() {// 什么都不做}@Overridepublic void run() {System.out.println("電梯運行");}@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}public class StoppingState extends LiftState {@Overridepublic void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.getLiftState().open();}@Overridepublic void close() {super.context.setLiftState(Context.CLOSING_STATE);super.context.getLiftState().close();}@Overridepublic void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.getLiftState().run();}@Overridepublic void stop() {System.out.println("電梯停止");}
}

測試類:

public class Client {public static void main(String[] args) {// 創建環境角色對象Context context = new Context();// 設置當前電梯狀態context.setLiftState(new ClosingState());context.open();context.close();context.run();context.stop();}
}

適用場景

  1. 當一個對象的行為取決于他的狀態,并且他必須在運行時根據狀態改變他的行為
  2. 一個操作中含有龐大的分支結構,并且這些分支決定于對象的狀態

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

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

相關文章

ubuntu22.04 卸載ESP-IDF

要在Ubuntu 22.04上完全卸載ESP-IDF&#xff0c;請按照以下步驟操作&#xff1a; 卸載ESP-IDF的步驟 刪除ESP-IDF目錄&#xff1a; # 假設ESP-IDF安裝在~/esp/esp-idf目錄 rm -rf ~/esp/esp-idf刪除ESP-IDF工具鏈和下載的工具&#xff1a; rm -rf ~/.espressif從PATH中移除ESP…

SQLMesh 內置宏詳解:@PIVOT等常用宏的核心用法與示例

本文系統解析 SQLMesh 的四個核心內置宏&#xff0c;涵蓋行列轉換的 PIVOT、精準去重的 DEDUPLICATE、靈活生成日期范圍的 DATE_SPINE&#xff0c;以及動態表路徑解析的 RESOLVE_TEMPLATE。通過真實案例演示參數配置與 SQL 渲染邏輯&#xff0c;并對比宏調用與傳統 SQL 的差異&…

基于Springboot + vue3實現的工商局商家管理系統

項目描述 本系統包含管理員、商家兩個角色。 管理員角色&#xff1a; 用戶管理&#xff1a;管理系統中所有用戶的信息&#xff0c;包括添加、刪除和修改用戶。 許可證申請管理&#xff1a;管理商家的許可證申請&#xff0c;包括搜索、修改或刪除許可證申請。 許可證審批管理…

第五部分:第五節 - Express 路由與中間件進階:廚房的分工與異常處理

隨著你的 Express 應用變得越來越大&#xff0c;所有的路由和中間件都寫在一個文件里會變得難以管理。這時候就需要將代碼進行拆分和組織。此外&#xff0c;一個健壯的后端應用必須能夠優雅地處理錯誤和一些常見的 Web 開發問題&#xff0c;比如跨域。 路由模塊化 (express.Ro…

萌新聯賽第(三)場

C題 這道題用暴力去寫想都不要想&#xff0c;一定超時&#xff0c;于是我們需要優化&#xff0c;下面是思路過程&#xff1a; 如圖&#xff0c;本題只需找到x的因數個數和(n-x)的因數個數&#xff0c;這兩個相乘&#xff0c;得到的就是對于這個x來說組合的個數&#xff0c;且x…

【Android構建系統】如何在Camera Hal的Android.bp中選擇性引用某個模塊

背景描述 本篇文章是一個Android.bp中選擇性引用某個模塊的實例。 如果是Android.mk編譯時期&#xff0c;在編譯階段通過某個條件判斷是不是引用某個模塊A, 是比較好實現的。Android15使用Android.bp構建后&#xff0c;要想在Android.bp中通過自定義的一個變量或者條件實現選…

【OneNET】_01_使用微信小程序通過新版OneNET平臺獲取STM32設備信息并進行控制

【OneNET】_01_使用微信小程序通過新版OneNET平臺獲取STM32設備信息并進行控制 一、 前言1.1 OntNET硬件方面: STM32F103C8T6 ESP01S教程 1.2 微信小程序方面 二、STM32代碼部分修改三、微信小程序修改的部分四、小筆記&#xff08;個人雜記&#xff09;4.1 OneNETOneNET物聯網…

用 python 編寫的一個圖片自動分類小程序(三)

圖片自動分類識別小程序記錄 2025/5/18 0:38修改程序界面&#xff0c;增加一些功能 用 python 編寫的一個圖片自動識別分類小程序。 操作系統平臺&#xff1a;Microsoft Windows 11 編程語言和 IDE&#xff1a;python 3.10 Visual studio code 一&#xff1a;圖片自動分…

嵌入式硬件篇---SGP30 氣體傳感器

文章目錄 前言一、SGP30 氣體傳感器詳解(一)基本概述(二)工作原理傳感器結構檢測機制自校準功能(三)主要特性(四)應用場景智能家居空氣質量檢測儀汽車行業商業建筑二、TVOC 與 eCO2 的含義(一)TVOC(總揮發性有機化合物)定義危害健康標準(二)eCO2(等效二氧化碳)…

【原創】ubuntu22.04下載編譯AOSP 15

安裝依賴的庫&#xff0c;順便把vim 也安裝一下 sudo apt-get install vim sudo apt-get install git gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip font…

防止勒索病毒的兜底方案——備份

勒索病毒入侵會對您的業務數據進行加密勒索&#xff0c;導致業務中斷、數據泄露、數據丟失等&#xff0c;從而帶來嚴重的業務風險。 防止勒索病毒有三個方向&#xff1a; 1&#xff09;實時防御已知勒索病毒 各個云廠商的云安全中心實現了對大量已知勒索病毒的實時防御。在服務…

es在已有歷史數據的文檔新增加字段操作

新增字段設置默認值 場景 在已經有大量數據的索引文檔上&#xff0c;增加新字段 技術實現 一.更新索引映射 通過PUT請求顯式定義新字段類型&#xff0c;確保后續寫入的文檔能被正確解析 PUT /文檔名/_mapping {"properties": {"字段名1": {"type…

留給王小川的時間不多了

王小川&#xff0c;這位頭頂“天才少年”光環的清華學霸、搜狗輸入法創始人、中國互聯網初代技術偶像&#xff0c;正迎來人生中最難啃的硬骨頭。 他在2023年創立的百川智能&#xff0c;被稱為“大模型六小虎”之一。今年4月&#xff0c;王小川在全員信中罕見地反思過去兩年工作…

深入掌握MyBatis:連接池、動態SQL、多表查詢與緩存

文章目錄 一、MyBatis連接池1.1 連接池的作用1.2 MyBatis連接池分類 二、動態SQL2.1 if標簽2.2 where標簽2.3 foreach標簽2.4 SQL片段復用 三、多表查詢3.1 多對一查詢&#xff08;一對一&#xff09;3.2 一對多查詢 四、延遲加載4.1 立即加載 vs 延遲加載4.2 配置延遲加載 五、…

TDesign AI Chat - Vue3.x 可用!騰訊出品的 AIGC 交互對話組件,免費開源、包含設計資源

各位前端開發者有遇到做 AI Chat 項目的聊天交互界面需求了嗎&#xff1f;TDesign 出品的這個組件很不錯&#xff0c;推薦給大家。 TDesign AI Chat 是 TDesign 為 AIGC 場景開發的 UI 系列組件中的一部分&#xff0c;主要用于開發目前非常流行的 ChatBot 對話交互場景。最近 …

spring -MVC-02

SpringMVC-11 - 響應 在 SpringMVC 中&#xff0c;響應是服務器對客戶端請求的反饋&#xff0c;它可以以多種形式呈現&#xff0c;包括視圖名稱、ModelAndView 對象、JSON 數據以及重定向等。以下是對 SpringMVC 中不同響應類型的詳細介紹&#xff1a; 1. 視圖名稱 通過返回…

老舊設備升級利器:Modbus TCP轉 Profinet讓能效監控更智能

在工業自動化領域&#xff0c;ModbusTCP和Profinet是兩種常見的通訊協議。Profinet是西門子公司推出的基于以太網的實時工業以太網標準&#xff0c;而Modbus則是由施耐德電氣提出的全球首個真正開放的、應用于電子控制器上的現場總線協議。這兩種協議各有各的優點&#xff0c;但…

ubuntu下docker安裝mongodb-支持單副本集

1.mogodb支持事務的前提 1) MongoDB 版本&#xff1a;確保 MongoDB 版本大于或等于 4.0&#xff0c;因為事務支持是在 4.0 版本中引入的。 2) 副本集配置&#xff1a;MongoDB 必須以副本集&#xff08;Replica Set&#xff09;模式運行&#xff0c;即使是單節點副本集&#x…

【前端開發】Uniapp日期時間選擇器:實現分鐘動態步長設置

技術棧 Uniapp + Vue3 + uView年份顯示前后一年,分鐘動態設置間隔效果圖 主體顯示<view class="uni-row-between selector"><view class="uni-flex-1 left" @click="!props.disabled && openPicker()"><uni-iconscolor=…

iOS 藍牙開發中的 BT 與 BLE

在 iOS 開發者的語境里&#xff0c;大家把 BT 和 BLE 當成兩種不同的藍牙技術在談——它們來自同一個 Bluetooth 規范&#xff0c;但面向的場景、協議棧乃至 Apple 提供的 API 都截然不同。 縮寫全稱 / 技術名稱規范層叫法iOS 支持現狀典型用途BTBluetooth Classic&#xff08…