《設計模式面試小炒》策略和工廠模式替代業務場景中復雜的ifelse

我是肥哥,一名不專業的面試官!
我是囧囧,一名積極找作業的小菜鳥!
囧囧表示:小白面試最怕的就是面試官問的知識點太籠統,自己無法快速定位到關鍵問題點!!!
本期主要面試考點
面試官考點之如何用設計模式替換業務場景中復雜的ifelse?


VIP型別
import java.util.Objects;
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 會員型別
*/
public enum VIPEnums {
GOLD(1, "黃金會員"),
STAR(2, "星鉆會員"),
SPORTS(3, "體育會員"),
FUN_VIP(4, "FUN會員");
private final int code;
private final String desc;
VIPEnums(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
public static VIPEnums getByCode(Integer code) {
for (VIPEnums s : VIPEnums.values()) {
if (Objects.equals(s.getCode(), code)) {
return s;
}
}
return null;
}
}
VIP物體
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* vip
*/
public class VIP {
private VIPEnums vipType;
// TODO VIP 其他屬性 id, name ...
public VIP() {
}
public VIP(VIPEnums vipType) {
this.vipType = vipType;
}
public VIPEnums getVipType() {
return vipType;
}
public void setVipType(VIPEnums vipType) {
this.vipType = vipType;
}
}
if-else 模式
// if-else 模式
public class App {
public static void main( String[] args ) {
// 黃金會員
VIP vip = new VIP(VIPEnums.GOLD);
if (vip.getVipType().getCode() == VIPEnums.GOLD.getCode()) {
// TODO 黃金會員權益
} else if (vip.getVipType().getCode() == VIPEnums.STAR.getCode()) {
// TODO 星鉆會員權益
} else if (vip.getVipType().getCode() == VIPEnums.SPORTS.getCode()) {
// TODO 體育會員權益
} else if (vip.getVipType().getCode() == VIPEnums.FUN_VIP.getCode()) {
// TODO FUN會員權益
} else {
// TODO 其他會員...
}
}
}
策略模式
VIP策略介面
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
* VIP 策略介面
*/
public interface VIPStrategy {
// VIP 具備的權益
void equity();
}
策略介面具體實作類-黃金會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 策略介面具體實作類-黃金會員
*/
public class GoldVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO 黃金會員具備的具體權益
}
}
策略介面具體實作類-星鉆會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 策略介面具體實作類-星鉆會員
*/
public class StarVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO 星鉆會員具備的具體權益
}
}
策略介面具體實作類-體育會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 策略介面具體實作類-體育會員
*/
public class SportsVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO 體育會員具備的具體權益
}
}
策略介面具體實作類-FUN會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 策略介面具體實作類-FUN會員
*/
public class FunVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO FUN會員具備的具體權益
}
}
策略背景關系類
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 策略背景關系類( vip 策略介面的持有者)
*/
public class VIPStrategyContext {
private VIPStrategy vipStrategy;
// 設定VIP策略
public void setVipStrategy(VIPStrategy vipStrategy) {
this.vipStrategy = vipStrategy;
}
// 執行 VIP 權益
public void handle() {
if (vipStrategy != null) {
vipStrategy.equity();
}
}
}
策略工廠
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* VIP策略工廠
*/
public class VIPStrategyFactory {
private VIPStrategyFactory() {
}
public static VIPStrategy getVipStrategy(VIP vip) {
VIPStrategy vipStrategy = null;
if (vip.getVipType().getCode() == VIPEnums.GOLD.getCode()) {
// 黃金會員策略實作類
vipStrategy = new GoldVIPStrategyImpl();
} else if (vip.getVipType().getCode() == VIPEnums.STAR.getCode()) {
// 星鉆會員策略實作類
vipStrategy = new StarVIPStrategyImpl();
} else if (vip.getVipType().getCode() == VIPEnums.SPORTS.getCode()) {
// 體育會員策略實作類
vipStrategy = new SportsVIPStrategyImpl();
} else if (vip.getVipType().getCode() == VIPEnums.FUN_VIP.getCode()) {
// FUN會員策略實作類
vipStrategy = new FunVIPStrategyImpl();
} else {
// 其他會員...
}
return vipStrategy;
}
}
模擬會員登錄獲取權益
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 模擬會員登錄獲取權益
*/
public class TestStrategy {
public static void main(String[] args) {
// 黃金會員
VIP vip = new VIP(VIPEnums.GOLD);
// 策略背景關系,執行者
VIPStrategyContext context = new VIPStrategyContext();
// 根據會員型別,獲取會員具體策略,獲取黃金會員策略
VIPStrategy strategy = VIPStrategyFactory.getVipStrategy(vip);
// 系結給執行者
context.setVipStrategy(strategy);
// 執行黃金會員的策略,黃金權益
context.handle();
}
}
我們知道, 策略模式的本身設計出來的目的是封裝一系列的演算法,這些演算法都具有共性,可以相互替換,演算法獨立于使用它的客戶端獨立變化,客戶端不需要了解關注演算法的具體實作,客戶端僅僅依賴于策略介面 ,
通過使用策略模式和工廠模式結合,是不是感覺變得高大上起來了呢???
當然了,最主要的是程式的擴展來說更方便了一些,更符合開閉原則,開放擴展,關閉修改,無論新增多少種新型別的會員,每個人只需要去繼承策略介面,實作新會員應有的權益即可,
注意,雖然利于擴展,但是策略模式的缺點也很明顯,策略工廠在創建具體的策略實作類的時候,還是書寫大量的 if-else 去進行判斷,如圖

有小伙伴就說了這和不使用策略模式和工廠模式似乎差不多???
抽出一個方法或者封裝成一個物件去呼叫豈不是更簡單???

接下來,我們就說說如何優化策略工廠,
首先,我們的工廠,是根據當前傳入的用戶的會員型別,判斷后,回傳相應的策略實作類,那么可以借助集合來存盤實作類,會員型別作為 key,將所有的會員策略都注冊到 map 中,需要注意的是,日常開發基于Spring進行bean管理,上面需要創建的策略類,當然都是希望被 Spring 動態托管,而不是我們自己去一個個的new 出實體,
問題是,如何去實作策略類通過spring進行托管注冊?
Spring種提供的InitializingBean介面,這個介面為Bean提供了屬性初始化后的處理方法,它只包括afterPropertiesSet方法,凡是繼承該介面的類,在bean的屬性初始化后都會執行該方法,我們利用此方法把Spring通過IOC創建出來的Bean注冊Map 中,
改造策略工廠
import org.example.model.VIP;
import org.example.strategy.VIPStrategy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
* <p>
* VIP策略工廠
*/
public class VIPStrategyFactory {
// 存盤策略類實體
public static Map<Integer, VIPStrategy> strategyMap = new ConcurrentHashMap<>();
private VIPStrategyFactory() {
}
public static VIPStrategy getVipStrategy(VIP vip) {
if (vip == null) {
return null;
}
return strategyMap.get(vip.getVipType().getCode());
}
}
改造策略類,在bean屬性初始化后,將實體物件注冊到工廠類中的 map
以黃金會員為例:
import org.example.factory.VIPStrategyFactory;
import org.example.model.VIPEnums;
import org.example.strategy.VIPStrategy;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: [email protected]
*
* 策略介面具體實作類-黃金會員
*/
@Service
public class GoldVIPStrategyImpl implements VIPStrategy, InitializingBean {
@Override
public void equity() {
// TODO 黃金會員具備的具體權益
System.out.println("黃金會員具備的具體權益");
}
@Override
public void afterPropertiesSet() throws Exception {
VIPStrategyFactory.strategyMap.put(VIPEnums.GOLD.getCode(), new GoldVIPStrategyImpl());
}
}
通過策略模式、工廠模式以及Spring的InitializingBean介面,算是解決了大量的if else,后續新VIP出現也更容易擴展,當然了,這里只是對于設計模式思想的一個簡單的示例,實際應用開發中,還是要根據具體的業務場景靈活變通,有需要的小伙伴也可以自己手動模擬一些場景,比如奶茶店各種奶茶新品等等,如果想用囧囧的示例,可公豬號上回復220110 自行匯入示例運行即可,
注意:學習軟體設計原則,千萬不能形成強迫癥,當碰到業務復雜的場景時,需要隨機應變,
學習設計原則是學習設計模式的基礎,在實際開發程序中,并不是一定要求所有代碼都遵循設計原則,而是要綜合考慮人力、時間、成本、質量,不刻意追求完美,要在適當的場景遵循設計原則,這體現的是一種平衡取舍,可以幫助我們設計出更加優雅的代碼結構,
設計模式其實也是一門藝術,設計模式源于生活,不要為了套用設計模式而使用設計模式,

喜歡的小伙伴,歡迎點贊收藏關注

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/415312.html
標籤:設計模式
上一篇:微服務架構 | *3.5 Nacos 服務注冊與發現的原始碼分析
下一篇:淺談23種設計模式之策略設計模式
