Java進階--設計模式

????????設計模式是一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石一樣,項目中合理地運用設計模式可以完美地解決很多問題。

? ? ? ? 設計模式多種多樣,這里參考設計模式簡介,本篇主要介紹最常用的幾種。

設計模式的分類

分類核心目標典型模式
創建型模式對象創建過程的抽象與優化工廠模式、抽象工廠、單例、建造者、原型
結構型模式對象與類的組織方式(組合結構優化)適配器、代理、裝飾者、橋接、組合、外觀、享元
行為型模式對象間的交互與職責分配(通信流程優化)
策略、觀察者、責任鏈、模板方法、命令、狀態、迭代器、中介者、備忘錄、訪問者

常用的設計模式

單例模式

????????單例模式(Singleton Pattern)是一種創建型設計模式,其核心目標是確保一個類僅有一個實例并提供該實例的全局訪問點。

????????特點:1.單例類只有一個實例對象。

? ? ? ? ? ? ? ? ? ?2.單例對象必須由單例類創建。

? ? ? ? ? ? ? ? ? ?3.對外提供一個訪問該單例的全局訪問點

核心實現方式

1. 餓漢式
  • 特點:類加載時立即創建實例,線程安全但可能造成資源浪費。

    public class EagerSingleton {// 類加載時初始化實例private static final EagerSingleton instance = new EagerSingleton();// 私有構造方法,防止外部實例化private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}
    }
2. 懶漢式
  • 特點:延遲實例化,首次調用時創建對象,需處理多線程安全問題。

基礎版(非線程安全)

public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}

?同步方法版(線程安全但性能低)

public class SynchronizedSingleton {private static SynchronizedSingleton instance;private SynchronizedSingleton() {}public static synchronized SynchronizedSingleton getInstance() {if (instance == null) {instance = new SynchronizedSingleton();}return instance;}
}

3. 雙重檢查鎖(Double-Checked Locking)?

  • 特點:延遲加載 + 線程安全 + 高性能,適用于多線程環境。

public class DCLSingleton {// 使用 volatile 防止指令重排序private static volatile DCLSingleton instance;private DCLSingleton() {}public static DCLSingleton getInstance() {if (instance == null) {                  // 第一次檢查synchronized (DCLSingleton.class) {  // 同步塊if (instance == null) {           // 第二次檢查instance = new DCLSingleton();}}}return instance;}
}

舉例:Runtime類

public class Runtime {private static Runtime currentRuntime = new Runtime();public static Runtime getRuntime() {return currentRuntime;}private Runtime() {}
}

?jdk中提供的類,標準的單例模式應用。

工廠模式

????????工廠模式(Factory Pattern)是一種創建型設計模式,其核心思想是將對象的創建邏輯與使用邏輯分離,通過統一的工廠接口或類來實例化對象,從而降低代碼耦合度并提升擴展性。

一、簡單工廠模式

定義

  • 核心:通過一個工廠類,根據傳入的參數決定創建哪種具體產品對象。

  • 適用場景:產品種類較少且創建邏輯簡單。

// 1. 定義產品接口
interface Car {void drive();
}// 2. 具體產品實現
class SedanCar implements Car {@Overridepublic void drive() {System.out.println("駕駛轎車");}
}class SUVCar implements Car {@Overridepublic void drive() {System.out.println("駕駛SUV");}
}// 3. 簡單工廠類
class CarFactory {public static Car createCar(String type) {switch (type.toLowerCase()) {case "sedan":return new SedanCar();case "suv":return new SUVCar();default:throw new IllegalArgumentException("未知的汽車類型");}}
}// 4. 使用示例
public class Client {public static void main(String[] args) {Car sedan = CarFactory.createCar("sedan");sedan.drive();  // 輸出:駕駛轎車Car suv = CarFactory.createCar("suv");suv.drive();    // 輸出:駕駛SUV}
}
????????工廠角色:簡單工廠模式的核心,它負責實現創建所有實例的內部邏輯。工廠類
提供靜態方法,可以被外界直接調用,創建所需的產品對象。
????????抽象產品角色:簡單工廠模式所創建的所有對象的父類,描述所有實例共有的接
口。可以是抽象類或接口。
????????具體產品角色:是簡單工廠模式的創建目標。

二、工廠方法模式

定義

  • 核心:定義抽象工廠接口,由子類決定具體實例化哪個類。每個產品對應一個工廠

public interface Car {void run();
}public class Aodi implements Car {@Overridepublic void run() {System.out.println("奧迪汽車行駛");}
}public class Bmw implements Car {@Overridepublic void run() {System.out.println("寶馬汽車行駛");}
}public interface CarFactory {Car createCar();
}public class AodiFactory implements  CarFactory{@Overridepublic Car createCar() {return new Aodi();}
}public class BmwFactory implements  CarFactory{@Overridepublic Car createCar() {return new Bmw();}
}public class Test {public static void main(String[] args) {CarFactory aodicarFactory = new AodiFactory();Car aodi =  aodicarFactory.createCar();aodi.run();CarFactory bmwcarFactory = new BmwFactory();Car bmw = bmwcarFactory.createCar();bmw.run();}
}

?一個產品對應一個工廠,奧迪車對應奧迪工廠,寶馬車對應寶馬工廠。

三、抽象工廠模式

定義

  • 核心:提供一個接口,用于創建相關或依賴對象的家族,而無需指定具體類。

public interface AbstractFactory {Car getCar();Phone getPhone();
}public interface Car {void run();
}public interface Phone {void  call();
}public class AodiFactory implements  AbstractFactory{@Overridepublic Car getCar() {return new AodiCar();}@Overridepublic Phone getPhone() {return new AodiPhone();}
}public class AodiCar implements Car{@Overridepublic void run() {System.out.println("奧迪汽車行駛");}
}public class AodiPhone implements Phone{@Overridepublic void call() {System.out.println("奧迪手機打電話");}
}public class BmwFactory implements AbstractFactory{@Overridepublic Car getCar() {return new BmwCar();}@Overridepublic Phone getPhone() {return new BmwPhone();}
}public class BmwCar implements Car{@Overridepublic void run() {System.out.println("寶馬汽車行駛");}
}public class BmwPhone implements Phone {@Overridepublic void call() {System.out.println("寶馬手機打電話");}
}public class Test {public static void main(String[] args) {AbstractFactory aodiFactory = new AodiFactory();Car aodiCar = aodiFactory.getCar();Phone aodiphone = aodiFactory.getPhone();aodiCar.run();aodiphone.call();AbstractFactory bmwFactory = new BmwFactory();Car bmwCar = bmwFactory.getCar();Phone bmwPhone = bmwFactory.getPhone();bmwCar.run();bmwPhone.call();}
}

?一個接口對應一個家族或者一個系列的東西,在這個案例中,就是奧迪工廠對應奧迪手機,奧迪車等等,寶馬抽象工廠對應寶馬手機和寶馬車。

三種工廠模式對比

模式核心區別適用場景
簡單工廠一個工廠類創建所有產品產品類型少,邏輯簡單
工廠方法每個產品對應一個工廠類需要靈活擴展產品類型
抽象工廠創建多個相關產品組成的家族需要保證產品族的兼容性

原型模式

????????原型模式(Prototype Pattern)是一種創建型設計模式,其核心思想是通過復制現有對象來創建新對象,而不是通過?new?關鍵字重新構造。

復制對象及其所有引用類型字段,創建完全獨立的新對象

class Address implements Cloneable {String city;public Address(String city) {this.city = city;}@Overridepublic Address clone() throws CloneNotSupportedException {return (Address) super.clone();}
}class User implements Cloneable {String name;Address address;public User(String name, Address address) {this.name = name;this.address = address;}// 深拷貝:遞歸復制引用類型字段@Overridepublic User clone() throws CloneNotSupportedException {User cloned = (User) super.clone();cloned.address = this.address.clone();  // 克隆Address對象return cloned;}
}// 使用示例
User user1 = new User("Alice", new Address("Beijing"));
User user2 = user1.clone();user2.address.city = "Shanghai";
System.out.println(user1.address.city);  // 輸出:Beijing(原對象未受影響)
優點缺點
提升性能,避免重復初始化深拷貝實現復雜(需遞歸克隆所有引用對象)
動態配置對象屬性需注意循環引用問題
繞過構造函數限制對不支持克隆的類需額外處理(如實現接口)

小結:原型模式通過復制現有對象高效創建新實例,尤其適用于對象初始化成本高或需要動態配置的場景。在實現時需注意?深拷貝與淺拷貝?的區別,避免因引用共享導致的數據不一致。合理使用原型模式,可以顯著優化性能并簡化復雜對象的創建邏輯。?

代理模式

????????代理模式(Proxy Pattern)是一種結構型設計模式,其核心思想是通過代理對象控制對原始對象的訪問,在不修改原始類的前提下增強功能或限制訪問。

代理模式的三種角色

  1. 抽象主題
    定義真實主題和代理主題的公共接口

  2. 真實主題
    實現業務邏輯的核心類

  3. 代理類
    持有真實主題的引用,控制對真實主題的訪問,并附加額外功能。

靜態代理

手動編寫代理類,代理類與真實類實現同一接口。

// 1. 抽象主題接口
interface UserService {void saveUser(String username);
}// 2. 真實主題
class UserServiceImpl implements UserService {public void saveUser(String username) {System.out.println("保存用戶: " + username);}
}// 3. 靜態代理類
class UserServiceProxy implements UserService {private UserService target;public UserServiceProxy(UserService target) {this.target = target;}public void saveUser(String username) {//通知System.out.println("[日志] 開始保存用戶...");target.saveUser(username);//通知System.out.println("[日志] 用戶保存完成");}
}// 使用示例
public class Client {public static void main(String[] args) {UserService realService = new UserServiceImpl();UserService proxy = new UserServiceProxy(realService);proxy.saveUser("Alice");}
}

?????????一個代理類可以對某一類的目標提供代理
????????滿足開閉原則(添加一類目標時,可以擴展添加一個新的代理類),
????????代碼是寫死的,不靈活

動態代理

????????在動態代理中我們不再需要再手動的創建代理類,我們只需要編寫一個動態處理器就可以了。真正的代理對象在運行時為我們動態的來創建。
?jdk代理

? ? ? ? 創建一個代理對象生成器,實現InvocationHandler,重寫invoke方法,這個方法會被代理對象動態調用,代理對象在運行時,被動態創建,可以代理任意的目標對象,提高靈活性。

? ? ? ? 注意被代理的目標對象,必須實現一個接口,在生成代理對象時,需要通過接口來獲取目標對象信息。

? ? ? ? 底層實現原理利用反射機制。

/*抽象操作定義 賣東西*/
public interface Sell {void sell();
}//目標類
public class CarFactoryImpl implements Sell {@Overridepublic void sell() {System.out.println("汽車廠賣汽車");}}/*動態代理類代理類不需要實現與目標類相同的接口,這樣就可以代理任意的目標類但是是有要求的,目標類必需實現接口,此種方式是動態代理的實現方式之一: jdk代理 是一種純反射機制實現(動態獲取目標類接口方法)*/
public class DynamicProxy implements InvocationHandler {Object object;//真實對象,接收任何的目標類對象public DynamicProxy(Object object) {this.object = object;}/*在代理類中調用目標類中的具體方法,動態的將代理動態對象,目標類中要調用的方法,及方法中的參數傳遞過來Method method  就是動態獲取的真正要執行的方法*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("之前開啟事務");method.invoke(object);System.out.println("之后提交事務");return proxy;}public Object getProxy(){return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);}
}public class Test {public static void main(String[] args) {CarFactoryImpl vip = new CarFactoryImpl();DynamicProxy dtproxy =  new DynamicProxy(vip);//自己創建的代理類對象//這才是真正的創建動態代理對象   獲取目標類所實現的接口Sell carfactory =    (Sell)dtproxy.getProxy();carfactory.sell();//使用代理對象調用接口中的方法,獲取當前調用的方法,最終調用invoke方法}
}
cglib代理

????????CGLib 采用了非常底層的字節碼技術,其原理是通過字節碼技術為一個類創建子類,并在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。

public  class CarFactoryImpl {public  void sell() {System.out.println("汽車廠賣汽車");}}import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** 動態代理類*/
public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public Object getProxy(Class<?> clazz){  enhancer.setSuperclass(clazz);  enhancer.setCallback(this);  return enhancer.create();  }  /** 攔截所有目標類方法的調用 * 參數: * obj  目標實例對象 * method 目標方法的反射對象 * args 方法的參數 * proxy 代理類的實例 */public Object intercept(Object obj, Method method, Object[] args,  MethodProxy proxy) throws Throwable {//代理類調用父類的方法  System.out.println("開始事務");  Object result = proxy.invokeSuper(obj, args);  System.out.println("關閉事務");  return result;  }
}
public class Test {public static void main(String[] args) {CGLibProxy proxy = new CGLibProxy();CarFactoryImpl carFactory = (CarFactoryImpl) proxy.getProxy(CarFactoryImpl.class);carFactory.sell();}
}

????????要求目標類不能是final修飾,方法也不能是final修飾的,和static修飾的.?

????????在spring框架中兩種代理生成機制都實現了:
????????????????可以根據目標是否實現接口自動選擇生成代理對象的方式,
????????????????默認采用cglib代理方式生成.?

代理模式通過間接訪問目標對象,實現了功能增強訪問控制,是解耦系統模塊、提升靈活性的重要手段。選擇代理類型時需注意:

  • 靜態代理:簡單場景,代理類少。

  • JDK 動態代理:基于接口,適合代理多個方法。

  • CGLIB 代理:代理無接口的類,需注意性能與限制。

適配器模式

????????適配器模式(Adapter Pattern)是一種結構型設計模式,用于將不兼容的接口轉換為客戶端期望的接口,使得原本無法協同工作的類能夠一起協作。其核心思想是通過一個“中間層”(適配器)解決接口不匹配問題,類似于現實中的電源轉接頭。

適配器模式的核心角色?

角色說明
目標接口(Target)客戶端期望的接口(如?XmlParser),定義客戶端調用的標準方法。
適配者(Adaptee)已存在的、需要被適配的接口或類(如?JsonParser),提供實際功能但接口不兼容。
適配器(Adapter)實現目標接口,并持有適配者的引用,通過轉換邏輯調用適配者的方法。
  • 特點:通過組合持有適配者對象,更靈活且符合合成復用原則。

  • 適用場景:適配者與目標接口差異較大,或需適配多個適配者。

// 目標接口
public interface XmlParser {void parseXml(String xml);
}// 適配者類
public class JsonParser {public void parseJson(String json) {System.out.println("解析JSON: " + json);}
}// 對象適配器(持有適配者引用,實現目標接口)
public class JsonToXmlAdapter implements XmlParser {private JsonParser jsonParser;public JsonToXmlAdapter(JsonParser jsonParser) {this.jsonParser = jsonParser;}public void parseXml(String xml) {String json = convertXmlToJson(xml); // 轉換邏輯jsonParser.parseJson(json);          // 調用適配者方法}private String convertXmlToJson(String xml) {//偽代碼return "Json"+xml,}
}

?測試

public class Test {public static void main(String[] args) {JsonParser jsonParser = new JsonParser();XmlParser xmlParser = new JsonToXmlAdapter(jsonParser);xmlParser.parseXml("<order id='123'/>");  // 輸出:解析JSON: { ... }}
}

其他案例:

Java I/O 中的適配器:將字節流轉換為字符流。

Spring MVC 的 HandlerAdapter:統一處理不同類型的控制器(如基于注解的?@Controller?和舊的?Controller?接口)。

小結:

適配器模式通過接口轉換解決不兼容問題,是集成遺留代碼或第三方庫的利器。

使用建議:

  • 優先選擇對象適配器,更靈活且符合組合復用原則。

  • 避免濫用適配器,若接口不匹配問題可通過重構解決,則無需引入適配器。

  • 在框架設計、系統集成、多格式兼容等場景中,適配器模式能顯著提升代碼復用性和擴展性。

模版方法模式

??????模板方法模式(Template Method Pattern)是一種行為型設計模式,其核心思想是定義一個算法的骨架,將某些步驟延遲到子類實現,使得子類可以在不改變算法結構的情況下重新定義某些步驟的具體實現。

角色說明
抽象類(Abstract Class)定義算法的骨架(模板方法),包含具體步驟和抽象方法。
具體子類(Concrete Class)實現抽象類中的抽象方法,完成特定步驟的具體邏輯。
模板方法(Template Method)抽象類中定義的算法流程,通常為?final?方法,防止子類重寫算法結構。
鉤子方法(Hook Method)抽象類中可選的方法,子類可選擇性覆蓋,用于影響算法流程。

舉個例子:客戶去銀行辦事,一般要經過以下 4 個流程:取號、排隊、辦理具體業務、對銀行工作人員進行評分等。但是去辦理的業務可能不同,可以延遲到子類中實現。

public abstract class AbstractBank {//辦理業務方法 -- 模板方法public void handle(){this.offerNumber();this.lineup();this.business();this.score();}//抽號public void offerNumber(){System.out.println("抽號");}//排隊public void lineup(){System.out.println("排隊");}//辦理具體業務--抽象方法,由具體子類實現public abstract void business();//評分public void score(){System.out.println("評分");}
}/*轉賬業務類*/
public class TransferBusiness  extends AbstractBank{//轉賬public void business() {System.out.println("我要轉賬");}}/*存錢業務*/
public class StoreBusiness extends AbstractBank{//辦理的具體業務public void business() {System.out.println("我要存錢");}
}
public class Test {public static void main(String[] args) {StoreBusiness storeBusiness = new StoreBusiness();storeBusiness.handle();System.out.println("===================================");TransferBusiness transferBusiness = new TransferBusiness();transferBusiness.handle();}
}

其他案例:

Servlet 的生命周期

????????Servlet 的?service()?方法是一個模板方法,處理 HTTP 請求的通用流程,子類(如?HttpServlet)通過重寫?doGet()doPost()?實現具體邏輯。

小潔:

模板方法模式通過固定算法骨架靈活步驟實現,在保證代碼復用性的同時支持擴展。其關鍵點在于:

  1. 定義模板方法:使用?final?修飾確保算法結構不被破壞。

  2. 抽象步驟方法:子類必須實現差異邏輯。

  3. 鉤子方法:提供可選擴展點,控制算法流程。

適用場景

  • 多個子類有共同行為,但部分步驟不同。

  • 需要控制子類擴展方式,避免破壞核心流程。

注意事項

  • 避免過度使用繼承,若算法步驟頻繁變化,可考慮策略模式。

  • 合理使用鉤子方法,保持代碼簡潔。

策略模式

????????策略模式(Strategy Pattern)是一種行為型設計模式,其核心思想是定義一系列算法,封裝每個算法,并使它們可以互相替換。策略模式讓算法的變化獨立于使用它的客戶端,通過動態切換算法實現靈活擴展,同時遵循開閉原則(對擴展開放,對修改關閉)。

角色說明
策略接口(Strategy)定義算法的公共接口(如?PaymentStrategy),所有具體策略必須實現該接口。
具體策略類(Concrete Strategy)實現策略接口,提供具體的算法實現(如支付寶支付、微信支付)。
上下文類(Context)持有策略對象,并委托具體策略執行算法(如訂單支付處理類)。

?案例:電商支付策略

//定義策略接口
interface PaymentStrategy {void pay(double amount);
}//實現具體策略類// 支付寶支付
class AlipayStrategy implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("支付寶支付: " + amount + "元");}
}// 微信支付
class WechatPayStrategy implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("微信支付: " + amount + "元");}
}//委托策略執行// 銀行卡支付
class BankCardStrategy implements PaymentStrategy {@Overridepublic void pay(double amount) {System.out.println("銀行卡支付: " + amount + "元");}
}class OrderPayment {private PaymentStrategy paymentStrategy;// 設置支付策略public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}// 執行支付public void executePayment(double amount) {if (paymentStrategy == null) {throw new IllegalStateException("未設置支付策略");}paymentStrategy.pay(amount);}
}//調用
public class Client {public static void main(String[] args) {OrderPayment order = new OrderPayment();// 使用支付寶支付order.setPaymentStrategy(new AlipayStrategy());order.executePayment(100.0);  // 輸出:支付寶支付: 100.0元// 切換為微信支付order.setPaymentStrategy(new WechatPayStrategy());order.executePayment(200.0);  // 輸出:微信支付: 200.0元}
}

總結

策略模式通過封裝算法動態切換策略,有效提升了系統的靈活性和可維護性。其核心優勢在于:

  • 解耦算法與業務邏輯:客戶端僅依賴抽象策略接口。

  • 簡化單元測試:每個策略可獨立測試。

  • 符合開閉原則:新增策略無需修改現有代碼。

適用場景

  • 系統需要多種算法變體,且需動態切換。

  • 存在復雜條件分支,需消除大量?if-else?或?switch?語句。

  • 算法需要獨立復用,或需隔離算法實現細節。

注意事項

  • 合理控制策略類數量,避免類膨脹。

  • 優先使用組合而非繼承,保持代碼靈活性。

觀察者模式

????????觀察者模式(Observer Pattern)是一種行為型設計模式,用于建立對象間的一對多依賴關系,當一個對象(被觀察者)的狀態發生改變時,所有依賴它的對象(觀察者)會自動收到通知并更新。

角色說明
被觀察者(Subject)維護觀察者列表,提供注冊、注銷和通知方法(如?addObserver(),?notifyObservers())。
觀察者(Observer)定義更新接口(如?update()),接收被觀察者的狀態變化通知。
具體被觀察者(Concrete Subject)實現業務邏輯,狀態變更時觸發通知(如訂單狀態變化)。
具體觀察者(Concrete Observer)實現?update()?方法,定義收到通知后的具體響應邏輯(如發送郵件、更新UI)。

案例:微信公眾號發文,用戶訂閱

//抽象觀察者
public interface Observer {void update(String message);}//抽象主題
public interface Subject {//增加訂閱者public void attach(Observer observer);//刪除訂閱者public void detach(Observer observer);//通知訂閱者更新消息public void notify(String message);
}//真實主體
public class SubscriptionSubject implements Subject {//儲存訂閱公眾號的微信用戶--觀察者private List<Observer> weixinUserlist = new ArrayList();//增加訂閱者@Overridepublic void attach(Observer observer) {weixinUserlist.add(observer);}//刪除訂閱者@Overridepublic void detach(Observer observer) {weixinUserlist.remove(observer);}//通知訂閱者更新消息@Overridepublic void notify(String message) {for (Observer observer : weixinUserlist) {observer.update(message);}}
}//真實觀察者
public class WeixinUser implements Observer{// 微信用戶名private String name;public WeixinUser(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + "-" + message);}}

調用

public class Test {public static void main(String[] args) {SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject();//創建微信用戶WeixinUser user1=new WeixinUser("張三");WeixinUser user2=new WeixinUser("李四");WeixinUser user3=new WeixinUser("王麻子");//訂閱公眾號mSubscriptionSubject.attach(user1);mSubscriptionSubject.attach(user2);mSubscriptionSubject.attach(user3);//公眾號更新發出消息給訂閱的微信用戶mSubscriptionSubject.notify("文章更新了");}}

?總結

觀察者模式通過事件通知機制實現對象間的動態聯動,是解耦復雜系統的有效工具。其核心價值在于:

  • 松耦合設計:主題與觀察者獨立演化。

  • 靈活擴展:動態增刪觀察者,無需修改主題。

  • 事件驅動:支持實時響應和異步處理。

適用場景

  • 需要實現一對多的消息通知。

  • 期望降低對象間的直接依賴。

  • 需構建靈活、可擴展的事件處理系統。

注意事項

  • 控制通知頻率,避免性能瓶頸。

  • 合理處理異常,防止單個觀察者失敗影響整體流程。

  • 結合具體需求選擇同步或異步通知方式。

推薦小說:大話設計模式

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

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

相關文章

如何禁止AutoCAD這類軟件聯網

推薦二、三方法&#xff0c;對其他軟件影響最小 一、修改Hosts文件 Hosts文件是一個存儲域名與IP地址映射關系的文本文件&#xff0c;通過修改Hosts文件可以將AutoCAD的域名指向本地回環地址&#xff08;127.0.0.1&#xff09;&#xff0c;從而實現禁止聯網的目的。具體步驟如…

深度學習框架搭建(Vscode/Anaconda/CUDA/Pytroch)

目錄 ??????一 Vscode安裝 二、Anaconda安裝 三、更新顯卡驅動 四、安裝CUDA 五、安裝Pytorch 六、Vscode配置 七、出現的問題匯總 ??????一 Vscode安裝 在 Windows 上安裝 訪問 VS Code 官網 https://code.visualstudio.com/&#xff0c;點擊 "Downl…

結構模式識別理論與方法

我們在前文《模式識別的基本概念與理論體系》中就已經提及“模式分類”。 具體內容看我的CSDN文章&#xff1a;模式識別的基本概念與理論體系-CSDN博客 模式的識別方法主要有統計模式識別方法和結構模式識別方法兩大類。統計模式識別方法提出得較早&#xff0c;理論也較成熟…

12.多邊形的三角剖分 (Triangulation) : Fisk‘s proof

目錄 1.Fisks proof Trangulation Coloring Domination Pigeon-Hold Principle Generation 2.Orthogonal Polygons (正交多邊形) Necessity of floor(n4) Sufficiency by convex Quadrilateralization Generalization 1.Fisks proof Trangulation 引入內對角線&…

面經-計算機網絡——OSI七層模型與TCP/IP四層模型的對比詳解

OSI七層模型與TCP/IP四層模型的對比詳解 一、圖示解析&#xff1a;分層封裝結構 你提供的圖清晰展示了網絡通信中從應用層到物理層的封裝過程&#xff0c;每一層都會對上層的數據加上自己的頭部信息&#xff08;Header&#xff09;&#xff1a; 應用層&#xff1a; 應用…

React Native本地存儲方案總結

1. AsyncStorage&#xff08;鍵值對存儲&#xff09; 適用場景&#xff1a;簡單鍵值對存儲&#xff08;如用戶配置、Token、緩存數據&#xff09;。特點&#xff1a;異步、輕量、API 簡單&#xff0c;但性能一般&#xff0c;不推薦存儲大量數據。安裝&#xff1a;npm install …

Arduino程序函數詳解與實際案例

一、Arduino程序的核心架構與函數解析 Arduino程序的核心由兩個函數構成:setup() 和 loop()。這兩個函數是所有Arduino代碼的骨架,它們的合理使用決定了程序的結構和功能。 1.1 setup() 函數:初始化階段 setup() 函數在程序啟動時僅執行一次,用于完成初始化配置,例如設置…

【Unity】使用Socket建立客戶端和服務端并進行通信的例子

Socket服務端: using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class SocketServer { public static Socket listenSocket;//監聽Socket public static List<Socket>…

Qt connect第五個參數

在 Qt 中&#xff0c;QObject::connect 函數的第五個參數用于指定 連接類型&#xff08;Qt::ConnectionType&#xff09;&#xff0c;它決定了信號與槽之間的通信方式。以下是各枚舉值的詳解及使用場景&#xff1a; 1. Qt::AutoConnection&#xff08;默認值&#xff09; 行為…

【2025域適應科研日報】

本筆記主要為了記錄自己的科研日報&#xff0c;前段時間剛開始想寫的初衷也是為了自己的思考不跑偏&#xff0c;但是有幾天又沒有堅持下來&#xff0c;看到一位學長的文章&#xff0c;發現這種形式還是很有必要的&#xff0c;所以自己也打算堅持記錄下來&#xff0c;由于還正在…

XrayR啟動失敗

公司要用服務器之間進行數據加密&#xff0c;這里用的XrayR 我使用的Centos 7。 我這里使用一鍵腳本安裝后&#xff0c;/etc/XrayR目錄下沒有配置文件。 解決方案 XrayR安裝時&#xff0c;系統沒有unzip工具&#xff0c;也是會安裝失敗的&#xff0c;因為Centos7已經停止維…

鴻蒙文件上傳-從前端到后端詳解,對比jq請求和鴻蒙arkts請求區別,對比new FormData()和鴻蒙arktsrequest.uploadFile

需要權限&#xff1a;ohos.permission.INTERNET 1.nodejs自定義書寫上傳后端接口 傳輸過來的數據放在files?.image下 router.post(/upload,(req, res) > {var form new multiparty.Form();form.uploadDirpublic/images/uploads; //上傳圖片保存的地址(目錄必須存在)fo…

編寫教育網站后端頁面筆記

callbacktitle.html 對應表: 對應的功能: 控制器層數據: 頁面沒有寫內容 chapter.html 對應表: questionbank ,intofloortime,questionBank,title,didtitles,option,answer,analyse 對應的功能:問題反饋頁面 控制器層數據(控制器類): ChapterQuestionbankTitle c…

日常開發小Tips:后端返回帶顏色的字段給前端

一般來說&#xff0c;展示給用戶的字體格式&#xff0c;都是由前端控制&#xff0c;展現給用戶&#xff1b; 但是當要表示某些字段的數據為異常數據&#xff0c;或者將一些關鍵信息以不同顏色的形式呈現給用戶時&#xff0c;而前端又不好判斷&#xff0c;那么就可以由后端來控…

用spring-boot-maven-plugin打包成單個jar有哪些缺點優化方案

Spring Boot 的 Fat JAR&#xff08;通過 spring-boot-maven-plugin 打包&#xff09;雖然簡化了部署&#xff0c;但也存在一些潛在缺點&#xff0c;需根據場景權衡&#xff1a; 1. 啟動速度較慢 原因&#xff1a; Fat JAR 需要在啟動時解壓并加載所有依賴的 JAR 文件到類路徑…

Flowable7.x學習筆記(十五)動態指定用戶分配參數啟動工作流程

前言 得益于之前我們的基礎工程準備&#xff0c;我們終于可以正式啟動工作流程了&#xff0c;在啟動之前我們需要分配一下每個用戶任務的用戶信息&#xff0c;其中有三個選擇&#xff1a;【辦理人】/【候選組】/【候選用戶】&#xff0c;我們需要將系統中的用戶ID填入作為固定參…

力扣hot100——98.驗證二叉搜索樹

題目鏈接&#xff1a;98. 驗證二叉搜索樹 - 力扣&#xff08;LeetCode&#xff09; 首先列舉一個錯誤代碼 class Solution { public:bool isValidBST(TreeNode* root) {if(rootnullptr) return true;if(root->right){if(root->right->val<root->val) return f…

數據結構學習之順序表

在C語言學習到一定階段之后&#xff0c;接下來我們就進入到了數據結構的部分內容。 目錄 數據結構與線性表 順序表 順序表分類&#xff1a; 接下來我們要寫一段代碼實現動態順序表。 首先我們需要準備三個文件&#xff1a; 1.接下來我們要定義一個數據表 2.當創建號我們的…

C# wpf

學習網址&#xff1a;控件的父類們 - WPF中文網 - 從小白到大佬 控件的父類&#xff1a; 由此我們可以得出結論&#xff0c;控件的父類們(準確的說&#xff0c;應該叫父類的父類的父類)&#xff0c;至少有如下幾個類型&#xff1a; DispatcherObjectDependencyObjectVisualU…

JavaEE-多線程實戰02

接上 多線程編程實戰01 第三個多線程程序 package thread.test;//定義了一個叫MyThread3的類&#xff0c;實現了Runable接口,所以它必須重寫run()方法 class MyThread3 implements Runnable {Overridepublic void run() {//線程執行的具體內容//進入一個無限循環&#xff0c;…