工廠模式 vs 策略模式:設計模式中的 “創建者” 與 “決策者”

在日常工作里,需求變動或者新增功能是再常見不過的事情了。而面對這種情況時,那些耦合度較高的代碼就會給我們帶來不少麻煩,因為在這樣的代碼基礎上添加新需求往往困難重重。為了保證系統的穩定性,我們在添加新需求時,最好避免直接修改前人編寫的代碼,否則可能會破壞原有的穩定結構。

接下來,我會為大家介紹兩種非常實用的設計模式 —— 工廠模式和策略模式。如果您已經對這兩種設計模式了如指掌,那么可以直接跳過下面的介紹內容。

下文中出現的案例代碼在:https://gitee.com/dingchen0000/blog-notes.git

工廠模式

介紹

在傳統的編程方式里,當我們需要使用某個對象時,就會直接使用new關鍵字去創建它,就好像我們自己親手打造一個工具,打造完成后就能馬上使用。但這種方式在項目規模變大、邏輯變復雜后,會帶來很多問題,而工廠模式的出現就是為了解決這些問題。

想象一下,我們在一個電子工廠里工作。你創造出了一個智能機器人,它有靈活的手臂(屬性)和穩健的輪子(屬性),能夠高效地替你組裝零件(方法)。在傳統模式下,你創造出這個機器人后,就可以直接給它下達指令,讓它開始工作。同樣,你的同事創造了一臺智能冰箱,它有超大的存儲空間(屬性)和智能的溫度調節功能(方法),你的同事也能直接操作這臺冰箱。

然而,如果有其他部門的同事想要使用你們創造的機器人和冰箱,就會變得很麻煩。他們需要分別找你和你的同事,經過你們的同意才能使用,這無疑增加了溝通成本和使用的復雜性。

為了解決這個問題,工廠引入了一個統一的管理部門(工廠模式)。你和你的同事把創造好的機器人和冰箱都交給這個管理部門,當其他部門的同事需要使用機器人或冰箱時,只需要向這個管理部門提出申請,管理部門就會根據需求提供相應的設備。這樣一來,使用者不需要關心設備是如何制造出來的,也不需要和具體的創造者溝通,大大提高了使用效率,降低了各個部門之間的耦合度。

在代碼的世界里也是一樣。假設我們有不同的促銷策略,比如打折、滿減、贈品等。如果沒有工廠模式,在需要使用這些策略時,我們就得在代碼里到處使用new關鍵字來創建策略對象,這樣會讓代碼變得混亂,而且一旦策略的創建邏輯發生變化,就需要修改大量的代碼。而使用工廠模式,我們可以把這些策略對象的創建邏輯封裝在一個工廠類里,當需要使用某個策略時,只需要向工廠類請求,由工廠類來創建并返回相應的對象,這樣就實現了對象的創建和使用的分離,降低了代碼的耦合度,提高了代碼的可維護性和可擴展性。

非工廠案例

在傳統編程中,當需要實現打折促銷功能時,通常會在業務邏輯代碼里直接創建并使用打折策略對象。下面結合你提供的代碼片段,以 Java 為例說明傳統做法:

傳統的模式

// 1. 定義促銷策略接口
interface PromotionStrategy {double calculateDiscount(double orderAmount);
}// 2. 實現具體策略類
class DiscountStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {return orderAmount * 0.2; // 8折優惠}
}class FullReduceStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {return orderAmount >= 200 ? 50 : 0; // 滿200減50}
}// 3. 業務邏輯直接依賴具體策略
class OrderServiceWithoutFactory {public double calculateFinalPrice(double amount, String strategyType) {PromotionStrategy strategy;// 直接在業務邏輯中創建對象if ("DISCOUNT".equalsIgnoreCase(strategyType)) {strategy = new DiscountStrategy();} else if ("FULL_REDUCE".equalsIgnoreCase(strategyType)) {strategy = new FullReduceStrategy();} else {throw new IllegalArgumentException("未知策略類型");}return amount - strategy.calculateDiscount(amount);}
}// 4. 客戶端調用
public class NonFactoryDemo {public static void main(String[] args) {OrderServiceWithoutFactory service = new OrderServiceWithoutFactory();double finalPrice = service.calculateFinalPrice(300, "DISCOUNT");System.out.println("最終價格: " + finalPrice);}
}
  • 在非工廠模式中,對象的創建邏輯直接嵌入在業務代碼里,這會導致以下幾個嚴重的維護問題:

    代碼分散問題

    在復雜系統中,對象創建可能散落在多個服務類、工具類甚至控制器中。例如:

    • 訂單服務中直接new DiscountStrategy()
    • 營銷活動模塊中new FullReduceStrategy()
    • 定時任務里也可能創建相同對象

    當需要修改或擴展功能時,你需要:

    1. 找出所有創建該對象的地方
    2. 逐一修改,可能遺漏某些角落
    3. 承擔引入新問題的風險

缺點:

依賴關系復雜

業務類不僅依賴抽象接口,還依賴具體實現類:

public class OrderServiceWithoutFactory {public double calculatePrice(double amount) {// 直接依賴具體類!PromotionStrategy strategy = new DiscountStrategy(); return strategy.calculate(amount);}
}

這種強依賴導致:

  • 新增策略時必須修改業務類代碼
  • 策略類的構造函數變化(如增加參數)會影響所有調用處
  • 難以進行單元測試(需實例化真實對象而非模擬對象)

在非工廠模式里,直接在業務代碼中「硬編碼」創建對象,就像把鑰匙藏在家里各個抽屜里 —— 看起來方便,實際用的時候全是麻煩:

代碼像撒豆子,改一處得翻遍全項目

想象你要給超市所有收銀臺的「打折功能」升級:

  • 原本「滿減策略」的代碼,可能藏在:
    • 收銀臺的結賬程序里(new FullReduceStrategy()
    • 會員系統的積分兌換模塊里(又一個new FullReduceStrategy()
    • 甚至后臺定時計算報表的腳本里(再來一個new FullReduceStrategy()

當你想修改滿減規則時

  • 得像偵探一樣,把全項目里所有寫著FullReduceStrategy的地方都找出來(可能漏找某個角落)
  • 每個地方都要改一遍代碼(比如把「滿 200 減 50」改成「滿 300 減 80」)
  • 改完還得擔心:有沒有漏掉某個地方?改完其他功能會不會出錯?
業務代碼和具體實現「鎖死」,牽一發而動全身

舉個生活例子:
你開了家奶茶店,菜單上寫著「招牌奶茶 = 紅茶 + 奶精 + 珍珠」(業務邏輯),但你直接在菜單里寫死了「用 A 牌紅茶、B 牌奶精」(依賴具體實現類)。

問題來了

  • 新增口味麻煩:想推出「綠茶版奶茶」,必須把菜單上所有「紅茶」字樣都改成「綠茶」(新增策略必須改業務代碼)。
  • 供應商換原料就崩潰:如果 A 牌紅茶停產,你得把菜單上所有「A 牌紅茶」換成「C 牌紅茶」(策略類構造函數修改,所有調用處都得改)。
  • 沒法模擬測試:想試試「用椰奶代替奶精」的效果,必須真的買椰奶回來試(單元測試時必須創建真實對象,沒法用模擬數據)。

用代碼舉例就是:

// 業務代碼直接「點名」要某個具體實現類
public class 收銀臺 {public double 計算價格(double 金額) {// 直接「new」一個具體的「滿減策略」,就像直接說「我要A牌紅茶」優惠策略 策略 = new 滿減策略(); return 金額 - 策略.計算優惠(金額);}
}

這樣寫死的后果就是:

  • 想換「打折策略」?必須改這里的new 滿減策略()new 打折策略()
  • 滿減策略的構造函數需要傳參(比如new 滿減策略(200, 50))?所有用到它的地方都得跟著改參數。

工廠模式案例

// 1. 定義促銷策略接口(與非工廠模式相同)
interface PromotionStrategy {double calculateDiscount(double orderAmount);
}// 2. 實現具體策略類(與非工廠模式相同)
class DiscountStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {return orderAmount * 0.2; // 8折優惠}
}class FullReduceStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {return orderAmount >= 200 ? 50 : 0; // 滿200減50}
}// 3. 創建工廠類
class PromotionStrategyFactory {public static PromotionStrategy createStrategy(String strategyType) {if ("DISCOUNT".equalsIgnoreCase(strategyType)) {return new DiscountStrategy();} else if ("FULL_REDUCE".equalsIgnoreCase(strategyType)) {return new FullReduceStrategy();} else {throw new IllegalArgumentException("未知策略類型");}}
}// 4. 業務邏輯通過工廠獲取策略
class OrderServiceWithFactory {public double calculateFinalPrice(double amount, String strategyType) {// 通過工廠獲取策略,不直接依賴具體類PromotionStrategy strategy = PromotionStrategyFactory.createStrategy(strategyType);return amount - strategy.calculateDiscount(amount);}
}// 5. 客戶端調用
public class FactoryDemo {public static void main(String[] args) {OrderServiceWithFactory service = new OrderServiceWithFactory();double finalPrice = service.calculateFinalPrice(300, "FULL_REDUCE");System.out.println("最終價格: " + finalPrice);}
}

工廠模式的好處顯然就是

  1. 單一修改點:新增策略只需在工廠類中注冊,無需修改業務代碼
  2. 依賴倒置:業務類只依賴工廠和抽象接口,不依賴具體實現
  3. 代碼復用:復雜的初始化邏輯只需在工廠中實現一次
  4. 統一管理:對象創建規則集中維護,便于新增功能和團隊協作
  5. 可測試性:可以輕松替換工廠實現(如使用模擬工廠)進行單元測試

總結

非工廠模式就像把「建房子的圖紙」和「搬磚的步驟」混在一起寫:

  • 簡單場景下看似省事,但項目變大后,代碼會像亂成一團的毛線 ——
    • 改一個功能要挖地三尺找代碼
    • 牽一發而動全身,改完一處崩十處
    • 想測試新功能,必須把真實對象全跑一遍

而工廠模式就像找了個「專業包工頭」(工廠類)專門管搬磚,業務代碼只需要告訴包工頭「我要蓋客廳還是臥室」,剩下的細節全由包工頭處理 —— 既干凈又省心。

策略模式

介紹

策略模式是一種行為型設計模式,其核心思想是:

  • 封裝算法族:將不同的算法(或策略)封裝成獨立的類,使它們可以相互替換。
  • 解耦算法與使用:讓算法的變化獨立于使用算法的客戶端,從而提高代碼的靈活性和可擴展性

打個比方
你去餐廳吃飯,菜單上有「糖醋排骨」「魚香肉絲」「麻婆豆腐」等菜品(這就是不同的「策略」)。

  • 你不需要自己進廚房炒菜(不用關心具體怎么做菜),只需要告訴服務員「我要哪道菜」(調用策略)。
  • 服務員(相當于「上下文類」)會根據你的選擇,通知廚房做對應的菜(切換策略)。

策略模式的核心就像這個過程:把不同的「做事方法」封裝起來,需要時隨時切換,而調用者不用知道具體怎么實現。

案例說明

先定義「優惠規則」的統一標準(策略接口)

就像餐廳菜單上寫著「所有菜品都要能算出價格」,我們先定一個接口:

public interface PromotionStrategy {double calculateDiscount(double orderAmount); // 不管怎么優惠,都要能算出優惠金額
}

作用:讓所有優惠規則(打折、滿減、贈品)都必須遵守這個「規矩」,方便后續統一管理。

每個優惠規則都是一個「獨立菜品」(具體策略類)
  • 打折策略

    :相當于「糖醋排骨」,具體做法是「打 8 折」:

    public class DiscountStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {return orderAmount * 0.2; // 直接算優惠金額}
    }
    
  • 滿減策略

    :相當于「魚香肉絲」,具體做法是「滿 200 減 50」:

    public class FullReduceStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {return orderAmount >= 200 ? 50 : 0; // 滿足條件才優惠}
    }
    
  • 贈品策略:相當于「麻婆豆腐」,做法是「滿 100 送贈品」(雖然不直接減錢,但也是一種策略):

    public class GiftStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double orderAmount) {if (orderAmount >= 100) {System.out.println("送你小風扇!"); // 執行贈品邏輯}return 0; // 金額不變}
    }
    

關鍵點:每個策略類都是「自包含」的,就像廚房的不同廚師各自負責一道菜,互相不干擾。

上下文類:相當于「服務員」,負責切換策略

以前沒有上下文類時,你得自己去廚房點菜(業務代碼直接調用策略類),現在有了服務員,你只需要告訴她:「我要吃糖醋排骨」(調用上下文類的方法,傳入策略類型)。

public class OrderContext {private PromotionStrategy currentStrategy; // 當前使用的策略(默認是空的)// 初始化時選一種策略(比如默認用打折)public OrderContext(PromotionStrategy strategy) {this.currentStrategy = strategy;}// 隨時換策略!就像吃飯時突然想換菜,告訴服務員就行public void changeStrategy(PromotionStrategy newStrategy) {this.currentStrategy = newStrategy;}// 計算最終價格:交給當前策略去處理public double calculateFinalPrice(double orderAmount) {return orderAmount - currentStrategy.calculateDiscount(orderAmount);}
}

為什么需要上下文類?

  • 解耦調用邏輯:業務代碼不用關心「怎么創建策略對象」,只需要告訴上下文「我要用哪個策略」。
  • 支持動態切換:比如用戶下單時先用「打折策略」,付款前突然發現有滿減活動,直接調用changeStrategy切換即可,不用改核心計算邏輯。

策略模式+工廠模式

在實際開發的時候呀,很少會只用到一種設計模式,一般都是好幾種設計模式一起用。咱們就拿這個優惠策略的例子來說吧。

這個系統里的優惠策略可不止一種哦。要是以后想再增加新的優惠策略,就會在 PromotionStrategyFactory 這個工廠里創建新的對象。比如說以后又有了新的優惠方式,也得在這個工廠里來創建對應的對象。這里用到了策略模式,只要新的優惠策略實現 PromotionStrategy 這個接口,把里面計算折扣優惠的方法重新寫一下,然后在工廠里把創建這個新策略對象的邏輯加上就行。

下面是 PromotionStrategyFactory 這個工廠類的代碼:

@Component
public class PromotionStrategyFactory {public PromotionStrategy createStrategy(String strategyType) {// 根據傳入的策略類型,用大寫來判斷switch (strategyType.toUpperCase()) {// 如果是 "DISCOUNT",就創建一個折扣策略對象case "DISCOUNT":return new DiscountStrategy();// 如果是 "FULL_REDUCE",就創建一個滿減策略對象case "FULL_REDUCE":return new FullReduceStrategy();// 如果是 "GIFT",就創建一個贈品策略對象case "GIFT":return new GiftStrategy();// 如果傳入的策略類型不認識,就拋出異常default:throw new IllegalArgumentException("未知策略類型: " + strategyType);}}
}

在控制器層,也就是和客戶端交互的地方,代碼是這樣的:

@RestController
@RequestMapping("/api/promotion")
public class PromotionController {// 自動注入訂單上下文對象@Autowiredprivate OrderContext orderContext;// 自動注入優惠策略工廠對象@Autowiredprivate PromotionStrategyFactory strategyFactory;// 處理 GET 請求,計算優惠后的價格@GetMapping("/calculate")public ResponseEntity<Map<String, Object>> calculate(@RequestParam double orderAmount, @RequestParam String strategyType) {try {// 1. 從工廠獲取對應的優惠策略實例PromotionStrategy strategy = strategyFactory.createStrategy(strategyType);// 2. 把獲取到的策略應用到訂單上下文中orderContext.changeStrategy(strategy);// 3. 調用訂單上下文的方法,計算出最終的價格double finalPrice = orderContext.calculateFinalPrice(orderAmount);// 4. 把計算結果放到一個 Map 里,作為響應返回Map<String, Object> result = new LinkedHashMap<>();result.put("開始價格", orderAmount);result.put("折扣類型", strategyType);result.put("最后的折扣", finalPrice);return ResponseEntity.ok(result);} catch (IllegalArgumentException e) {// 如果傳入的策略類型不合法,就返回一個錯誤響應Map<String, Object> error = new LinkedHashMap<>();error.put("error", "INVALID_STRATEGY");error.put("message", e.getMessage());return ResponseEntity.badRequest().body(error);}}
}

簡單來說呢,就是通過工廠類來創建不同的優惠策略對象,然后在控制器里把這些策略應用到訂單上,計算出最終的優惠價格,要是遇到不認識的策略類型,還會給出錯誤提示。
在這里插入圖片描述
在這里插入圖片描述

改進(枚舉+sprinboot自動注冊)

在咱們現在用的工廠類里,代碼采用的是硬編碼方式。這就意味著,要是有新的優惠策略類加入,就得去修改工廠方法的代碼。可在開發中,頻繁修改代碼是我們不想看到的,因為這可能會引入新的問題,也不利于代碼的維護和擴展。

簡單工廠模式確實幫我們把客戶端和具體的策略類實現分離開來了,讓它們之間的依賴關系沒那么緊密。不過呢,工廠類在初始化策略對象(也就是策略 beans)的時候,還是和具體的策略類綁得比較緊。也就是說,工廠類得明確知道有哪些具體的策略類,這就導致一旦有新的策略類出現,工廠類就得跟著改。

為了讓它們之間的關系更松散,我們可以借助 Spring 框架里的 InitializingBean 接口和 ApplicationContextAware 接口來自動完成策略對象的裝配工作。

在這里插入圖片描述
下面來詳細說說這兩個接口的作用:

InitializingBean 接口

InitializingBean 接口有一個 afterPropertiesSet 方法。當 Spring 容器創建并初始化一個實現了 InitializingBean 接口的類的實例時,在設置完所有屬性之后,會自動調用 afterPropertiesSet 方法。我們可以在這個方法里完成一些初始化操作。

ApplicationContextAware 接口

ApplicationContextAware 接口有一個 setApplicationContext 方法。實現了這個接口的類可以通過該方法獲取到 Spring 的 ApplicationContext(應用上下文)。ApplicationContext 就像是 Spring 容器的大管家,它能管理所有的 Bean,我們可以通過它獲取到容器中所有實現了某個接口的 Bean 實例。

實現自動裝配策略對象

結合這兩個接口,我們可以在工廠類里這樣做:

  1. 實現 InitializingBean 接口,在 afterPropertiesSet 方法中進行策略對象的初始化操作。
  2. 實現 ApplicationContextAware 接口,通過 setApplicationContext 方法獲取 ApplicationContext
  3. 使用 ApplicationContextgetBeansOfType 方法獲取所有實現了 PromotionStrategy 接口的 Bean 實例,并將它們存到一個 Map 里。

這樣,當有新的策略類添加時,只要它實現了 PromotionStrategy 接口,Spring 容器會自動把它注冊為一個 Bean,afterPropertiesSet 方法會把它添加到 Map 中,工廠類就不需要再手動修改代碼來創建新的策略對象,從而實現了工廠類和具體策略類的解耦。

@Component
public class PromotionFactory implements InitializingBean {private final Map<PromotionType, PromotionStrategy> strategyMap = new HashMap<>();private final ApplicationContext applicationContext;@Autowiredpublic PromotionFactory(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}/*** 初始化:從Spring容器中獲取所有策略Bean,并按枚舉類型注冊* Key:Bean 的名稱(默認是類名首字母小寫,如fullReduceStrategy)。* Value:Bean 的實例(實現了PromotionStrategy接口的具體策略類)。*/@Overridepublic void afterPropertiesSet() {// 獲取所有實現PromotionStrategy接口的BeanMap<String, PromotionStrategy> beans = applicationContext.getBeansOfType(PromotionStrategy.class);beans.forEach((beanName, strategy) -> {// 從策略Bean中獲取對應的枚舉類型(需在策略類中增加獲取類型的方法)// 這里假設策略類通過枚舉類型命名(如FullReduceStrategy對應FULL_REDUCE枚舉)PromotionType type = parseTypeFromBeanName(beanName);if (type != null) {strategyMap.put(type, strategy);}});}/*** 從Bean名稱解析枚舉類型(簡化實現,實際可通過注解或接口方法指定類型)*/private PromotionType parseTypeFromBeanName(String beanName) {try {// Bean名稱默認駝峰式,轉為枚舉大寫return PromotionType.valueOf(beanName.toUpperCase());} catch (IllegalArgumentException e) {return null;}}/*** 獲取策略實例*/public PromotionStrategy getStrategy(PromotionType type) {if (!strategyMap.containsKey(type)) {throw new IllegalArgumentException("未知促銷類型:" + type);}return strategyMap.get(type);}
}
@Getter
public enum PromotionType {FULL_REDUCE("滿減"),DISCOUNT("打折"),GIFT("贈品");private final String desc;PromotionType(String desc) {this.desc = desc;}
}

在這里插入圖片描述

@RestController
public class TestController {private final OrderService orderService;public TestController(OrderService orderService) {this.orderService = orderService;}/*** 測試接口* http://localhost:8080/calculate?orderAmount=300&promotionType=FULL_REDUCE*/@GetMapping("/calculate")public String calculatePrice(@RequestParam double orderAmount, @RequestParam PromotionType promotionType) {double finalPrice = orderService.calculateFinalPrice(orderAmount, promotionType);return "訂單金額:" + orderAmount + "元,使用" + promotionType.getDesc() + "后,最終價格:" + finalPrice + "元";}
}

調用的模型圖

在這里插入圖片描述

ice = orderService;
}

/*** 測試接口* http://localhost:8080/calculate?orderAmount=300&promotionType=FULL_REDUCE*/
@GetMapping("/calculate")
public String calculatePrice(@RequestParam double orderAmount, @RequestParam PromotionType promotionType) {double finalPrice = orderService.calculateFinalPrice(orderAmount, promotionType);return "訂單金額:" + orderAmount + "元,使用" + promotionType.getDesc() + "后,最終價格:" + finalPrice + "元";
}

}

調用的模型圖[外鏈圖片轉存中...(img-GYDzYNR0-1748529814600)]

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

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

相關文章

Java web學習路徑預覽

Java web學習路徑預覽 &#xff08;圖源&#xff1a;黑馬程序員&#xff09; 目錄 Java web學習路徑預覽 一、HTML、CSS、JS 1. HTML (HyperText Markup Language): 網頁的骨架 2. CSS (Cascading Style Sheets): 網頁的皮膚 3. JavaScript (JS): 網頁的行為 二、Ajax、…

linux、docker、git相關操作

1 linux 1.1解壓縮 1.1.1 zip zip xxx.zip file 把名為fle的文件壓縮成xxx.zip -r 遞歸壓縮&#xff1a;加上該選項才能壓縮文件夾 zip -r example_new.zip 示例集 # 新建壓縮包并命名為 example_new.zip zip -r xxx.zip file1 file2 dir1 將多個文件目錄壓成zip包 unzip fi…

Attention Is All You Need (Transformer) 以及Transformer pytorch實現

參考https://zhuanlan.zhihu.com/p/569527564 Attention Is All You Need (Transformer) 是當今深度學習初學者必讀的一篇論文。 一. Attention Is All You Need (Transformer) 論文精讀 1. 知識準備 機器翻譯&#xff0c;就是將某種語言的一段文字翻譯成另一段文字。 由…

深入淺出:Oracle 數據庫 SQL 執行計劃查看詳解(1)——基礎概念與查看方式

背景 在當今的軟件開發領域&#xff0c;盡管主流開發模式往往傾向于采用單表模式&#xff0c;力圖盡可能地減少表之間的連接操作&#xff0c;以期達到提高數據處理效率、簡化應用邏輯等目的。然而&#xff0c;對于那些已經上線運行多年的運維老系統而言&#xff0c;它們內部往…

每天掌握一個Linux命令 - fail2ban

Linux 命令工具 fail2ban 使用指南 目錄 Linux 命令工具 fail2ban 使用指南一、工具概述二、安裝方式1. 包管理器安裝&#xff08;推薦&#xff09;Debian/Ubuntu 系統CentOS/RHEL 系統Arch Linux 系統 2. 手動編譯安裝&#xff08;適用于自定義需求&#xff09; 三、核心功能四…

互聯網大廠智能體平臺體驗筆記字節扣子羅盤、阿里云百煉、百度千帆 、騰訊元器、TI-ONE平臺、云智能體開發平臺

互聯網大廠 字節扣子、阿里云百煉、百度千帆 、騰訊元器、TI-ONE平臺、云智能體開發平臺 體驗 開始動手 了解 智能體&#xff0c;發現已經落后時代太遠 光頭部互聯網大廠對開 公開的平臺就已經這么多&#xff0c;可以學習和了解&#xff0c;相關的信息 整理了對應的平臺地址…

ansible-playbook 進階 接上一章內容

1.異常中斷 做法1&#xff1a;強制正常 編寫 nginx 的 playbook 文件 01-zuofa .yml - hosts : web remote_user : root tasks : - name : create new user user : name nginx-test system yes uid 82 shell / sbin / nologin - name : test new user shell : gete…

LRC and VIP

//首先排除所有數相等的情況,再把最大值放在一個組&#xff0c;那么最大值的gcd就等于其本身&#xff0c;再判斷剩下的gcd是否等于最大值就可以了 #include<bits/stdc.h> using namespace std;const int N1e3100; int a[N]; map<int,int>mapp; int main(){int t;ci…

企業應用AI對向量數據庫選型思考

一、向量數據庫概述 向量數據庫是一種專門用于存儲和檢索高維向量數據的數據庫系統&#xff0c;它能夠高效地處理基于向量相似性的查詢&#xff0c;如最近鄰搜索等&#xff0c;在人工智能、機器學習等領域的應用中發揮著重要作用&#xff0c;為處理復雜的向量數據提供了有力的…

設計模式——迭代器設計模式(行為型)

摘要 本文詳細介紹了迭代器設計模式&#xff0c;這是一種行為型設計模式&#xff0c;用于順序訪問集合對象中的元素&#xff0c;同時隱藏集合的內部結構。文章首先定義了迭代器設計模式并闡述了其核心角色&#xff0c;包括迭代器接口、具體迭代器、容器接口和具體容器。接著&a…

Java8 list集合根據屬性分組

在Java8中&#xff0c;可以使用Collectors.groupingBy方法對List集合根據屬性進行分組。以下是一個完整的示例&#xff0c;展示如何根據對象的不同屬性分組。 根據對象屬性分組 假設有一個Student類&#xff0c;包含name、age和grade屬性&#xff1a; public class Student …

更新已打包好的 Spring Boot JAR 文件中的 class 文件

# 1. 解壓原始 JAR unzip -q original-app.jar -d temp # 2. 替換 class 文件 cp ~/projects/new-classes/*.class temp/BOOT-INF/classes/com/example/ # 3. 保留原始清單 cp temp/META-INF/MANIFEST.MF . # 4. 重新打包 jar -cf0m new-app.jar MANIFEST.MF -C temp/ . # …

《HelloGitHub》第 110 期

興趣是最好的老師&#xff0c;HelloGitHub 讓你對開源感興趣&#xff01; 簡介 HelloGitHub 分享 GitHub 上有趣、入門級的開源項目。 github.com/521xueweihan/HelloGitHub 這里有實戰項目、入門教程、黑科技、開源書籍、大廠開源項目等&#xff0c;涵蓋多種編程語言 Python、…

當 “歐洲版 Cursor” 遇上安全危機

在 AI 編程助手蓬勃發展的當下&#xff0c;安全問題正成為行業不容忽視的隱憂。近期&#xff0c;AI 編程助手公司 Replit 與號稱 “歐洲版 Cursor” 的 Lovable 之間&#xff0c;因安全漏洞問題掀起了一場風波&#xff0c;引發了業界的廣泛關注。? Replit 的員工 Matt Palmer…

centos掛載目錄滿但實際未滿引發系統宕機

測試服務器應用系統突然掛了&#xff0c;經過排查發現是因為磁盤“滿了”導致的&#xff0c;使用df -h查看磁盤使用情況/home目錄使用率已經到了100%,但使用du -sh /home查看發現實際磁盤使用還不到1G&#xff0c;推測有進程正在寫入或占用已刪除的大文件&#xff08;Linux 系統…

乾坤qiankun的使用

vue2 為主應用 react 為子應用 在項目中安裝乾坤 yarn add qiankun # 或者 npm i qiankun -Svue主應用 在main.js中新增 &#xff08;需要注意的是路由模型為history模式&#xff09; registerMicroApps([{name: reactApp,entry: //localhost:3011,container: #container,/…

PostgreSQL的擴展 auth_delay

PostgreSQL的擴展 auth_delay auth_delay 是 PostgreSQL 提供的一個安全相關擴展&#xff0c;主要用于防止暴力破解攻擊。它通過在認證失敗后引入人為延遲來增加暴力破解的難度。 一、擴展基礎 功能&#xff1a;在認證失敗后增加延遲目的&#xff1a;減緩暴力破解和字典攻擊…

Web前端為什么要打包?Webpack 和 Vite 如何助力現代開發?

一. 為什么要使用框架庫? 1.1 傳統網頁與現代前端的差異 在最早期的網頁開發中,我們只需要寫幾個.html文件,配上.css和.js文件,瀏覽器直接加載就能展現頁面,每個文件都是獨立的靜態資源,簡單且直觀 但現在網站越來越復雜了: 需要用到最新的js語法(比如ES6)使用框架(Vue…

使用pdm+uv替換poetry

用了好幾年poetry了&#xff0c;各方面都還挺滿意&#xff0c;就是lock實在太慢&#xff1b; 已經試用pdmuv一段時間了&#xff0c;確實是快&#xff0c;也基本能覆蓋poetry的功能。 至于為什么用pdmuv&#xff0c;而不是只用uv&#xff0c;原因很多&#xff0c;有興趣的可以…

java后端生成心電圖-jfreechart

用jfreechart生成心電圖 先上成功的圖片 上代碼 1.導入包 implementation org.jfree:jfreechart:1.5.4implementation org.jfree:jcommon:1.0.242.實現代碼 對數據進行濾波 轉換單位 package com.shinrun.infrastructure.util;import java.util.ArrayList; import java.ut…