我是肥哥上鞠,一名不專業(yè)的面試官!
我是囧囧芯丧,一名積極找工作的小菜鳥芍阎!
囧囧表示:小白面試最怕的就是面試官問的知識點太籠統(tǒng),自己無法快速定位到關鍵問題點SШ恪G聪獭!
本期主要面試考點
面試官考點之如何用設計模式替換業(yè)務場景中復雜的ifelse肿轨?
VIP類型
import java.util.Objects;
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 會員類型
*/
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: jiongmeifeishi@163.com
*
* 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: jiongmefeishi@163.com
* VIP 策略接口
*/
public interface VIPStrategy {
// VIP 具備的權益
void equity();
}
策略接口具體實現(xiàn)類-黃金會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 策略接口具體實現(xiàn)類-黃金會員
*/
public class GoldVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO 黃金會員具備的具體權益
}
}
策略接口具體實現(xiàn)類-星鉆會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 策略接口具體實現(xiàn)類-星鉆會員
*/
public class StarVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO 星鉆會員具備的具體權益
}
}
策略接口具體實現(xiàn)類-體育會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 策略接口具體實現(xiàn)類-體育會員
*/
public class SportsVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO 體育會員具備的具體權益
}
}
策略接口具體實現(xiàn)類-FUN會員
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 策略接口具體實現(xiàn)類-FUN會員
*/
public class FunVIPStrategyImpl implements VIPStrategy {
@Override
public void equity() {
// TODO FUN會員具備的具體權益
}
}
策略上下文類
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 策略上下文類( vip 策略接口的持有者)
*/
public class VIPStrategyContext {
private VIPStrategy vipStrategy;
// 設置VIP策略
public void setVipStrategy(VIPStrategy vipStrategy) {
this.vipStrategy = vipStrategy;
}
// 執(zhí)行 VIP 權益
public void handle() {
if (vipStrategy != null) {
vipStrategy.equity();
}
}
}
策略工廠
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* VIP策略工廠
*/
public class VIPStrategyFactory {
private VIPStrategyFactory() {
}
public static VIPStrategy getVipStrategy(VIP vip) {
VIPStrategy vipStrategy = null;
if (vip.getVipType().getCode() == VIPEnums.GOLD.getCode()) {
// 黃金會員策略實現(xiàn)類
vipStrategy = new GoldVIPStrategyImpl();
} else if (vip.getVipType().getCode() == VIPEnums.STAR.getCode()) {
// 星鉆會員策略實現(xiàn)類
vipStrategy = new StarVIPStrategyImpl();
} else if (vip.getVipType().getCode() == VIPEnums.SPORTS.getCode()) {
// 體育會員策略實現(xiàn)類
vipStrategy = new SportsVIPStrategyImpl();
} else if (vip.getVipType().getCode() == VIPEnums.FUN_VIP.getCode()) {
// FUN會員策略實現(xiàn)類
vipStrategy = new FunVIPStrategyImpl();
} else {
// 其他會員...
}
return vipStrategy;
}
}
模擬會員登錄獲取權益
/**
* @author: 歡迎關注喂信公豬號:囧么肥事
* @date: 2021/12/16
* @email: jiongmefeishi@163.com
*
* 模擬會員登錄獲取權益
*/
public class TestStrategy {
public static void main(String[] args) {
// 黃金會員
VIP vip = new VIP(VIPEnums.GOLD);
// 策略上下文寿冕,執(zhí)行者
VIPStrategyContext context = new VIPStrategyContext();
// 根據(jù)會員類型,獲取會員具體策略椒袍,獲取黃金會員策略
VIPStrategy strategy = VIPStrategyFactory.getVipStrategy(vip);
// 綁定給執(zhí)行者
context.setVipStrategy(strategy);
// 執(zhí)行黃金會員的策略驼唱,黃金權益
context.handle();
}
}
我們知道, 策略模式的本身設計出來的目的是封裝一系列的算法驹暑,這些算法都具有共性玫恳,可以相互替換,算法獨立于使用它的客戶端獨立變化优俘,客戶端不需要了解關注算法的具體實現(xiàn)京办,客戶端僅僅依賴于策略接口 。
通過使用策略模式和工廠模式結(jié)合帆焕,是不是感覺變得高大上起來了呢惭婿???
當然了,最主要的是程序的擴展來說更方便了一些叶雹,更符合開閉原則财饥,開放擴展,關閉修改折晦。無論新增多少種新類型的會員钥星,每個人只需要去繼承策略接口,實現(xiàn)新會員應有的權益即可满着。
注意谦炒,雖然利于擴展,但是策略模式的缺點也很明顯风喇,策略工廠在創(chuàng)建具體的策略實現(xiàn)類的時候宁改,還是書寫大量的 if-else 去進行判斷,如圖
有小伙伴就說了這和不使用策略模式和工廠模式似乎差不多响驴?透且??
抽出一個方法或者封裝成一個對象去調(diào)用豈不是更簡單豁鲤?秽誊??
接下來琳骡,我們就說說如何優(yōu)化策略工廠锅论。
首先,我們的工廠楣号,是根據(jù)當前傳入的用戶的會員類型最易,判斷后,返回相應的策略實現(xiàn)類炫狱,那么可以借助集合來存儲實現(xiàn)類藻懒,會員類型作為 key,將所有的會員策略都注冊到 map 中视译。需要注意的是嬉荆,日常開發(fā)基于Spring進行bean管理,上面需要創(chuàng)建的策略類酷含,當然都是希望被 Spring 動態(tài)托管鄙早,而不是我們自己去一個個的new 出實例。
問題是椅亚,如何去實現(xiàn)策略類通過spring進行托管注冊?
Spring種提供的InitializingBean
接口限番,這個接口為Bean提供了屬性初始化后的處理方法,它只包括afterPropertiesSet
方法呀舔,凡是繼承該接口的類弥虐,在bean
的屬性初始化后都會執(zhí)行該方法。我們利用此方法把Spring
通過IOC
創(chuàng)建出來的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: jiongmefeishi@163.com
* <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: jiongmefeishi@163.com
*
* 策略接口具體實現(xiàn)類-黃金會員
*/
@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,后續(xù)新VIP出現(xiàn)也更容易擴展豺妓,當然了惜互,這里只是對于設計模式思想的一個簡單的示例,實際應用開發(fā)中琳拭,還是要根據(jù)具體的業(yè)務場景靈活變通训堆。有需要的小伙伴也可以自己手動模擬一些場景,比如奶茶店各種奶茶新品等等白嘁。如果想用囧囧的示例坑鱼,可公豬號上回復220110 自行導入示例運行即可。
注意:學習軟件設計原則,千萬不能形成強迫癥鲁沥。當碰到業(yè)務復雜的場景時呼股,需要隨機應變。
學習設計原則是學習設計模式的基礎画恰。在實際開發(fā)過程中彭谁,并不是一定要求所有代碼都遵循設計原則,而是要綜合考慮人力允扇、時間缠局、成本、質(zhì)量考润,不刻意追求完美狭园,要在適當?shù)膱鼍白裱O計原則。這體現(xiàn)的是一種平衡取舍糊治,可以幫助我們設計出更加優(yōu)雅的代碼結(jié)構唱矛。
設計模式其實也是一門藝術。設計模式源于生活俊戳,不要為了套用設計模式而使用設計模式揖赴。
喜歡的小伙伴,歡迎點贊收藏關注