在平時開發中,有時避免不了使用大量判斷,簡單處理的話就使用if...else...了,但過多層的if else對於性能有很大的開銷,而且業務復雜的話,耦合太重,對於后期的拓展也不是很友好,所以使用策略模式。
1. 策略+工廠實現相同業務抽象
策略模式:一種解耦的方法,它對算法進行封裝,使得算法的調用和算法本身分離。使用策略模式客戶端代碼不需要調整,算法之間可以互相替換,因為不同的算法實現的是同一個接口。策略模式是一種對象行為型模式。策略模式符合“開閉原則”。
策略模式包括如下角色:
-
Context :環境類
-
Strategy:抽象策略類
-
ConcreteStrategy:具體策略類
下面簡單抽象下業務邏輯:
String name = "shaqiang"; if(name.equals("saobin")){ System.out.println("I am SaoBin"); }else if(name.equals("shaqiang")){ System.out.println("I am ShaQiang"); }else if(name.equals("weifeng")){ System.out.println("I am WeiFeng"); }
有成員“騷斌”、“傻強”、“偉峰”···,其執行邏輯基本一樣,基於策略模式對其進行改造:
1.1 定義策略接口
將成員的業務方法抽象為統一的策略接口。其中 InitializingBean 接口來自Spring框架,用於實現環境的統一工廠。
import org.springframework.beans.factory.InitializingBean; /** * 策略總接口*/ public interface NameHandler extends InitializingBean { /** * 輸出名稱 * @param name */ public void myName(String name); }
1.2 實現策略工廠
此處的工廠即策略模式下的 “環境類” 要素,功能為根據不同的name找到其對應的不同的策略實現,實現方法為將實現NameHandler接口的類都裝載到strategyMap里,除使用工廠實現外,也可以使用枚舉+代理實現。
import org.springframework.util.StringUtils; import java.util.HashMap; import java.util.Map; /** * 工廠設計模式*/ public class NameSetFactory { private static Map<String, NameHandler> strategyMap = new HashMap<>(); /** * 根據name獲取對應的handler實現 * @param name * @return */ public static NameHandler getInvokeStrategyMap(String name){ return strategyMap.get(name); } /** * 注冊 * @param name * @param handler */ public static void register(String name, NameHandler handler){ if(StringUtils.isEmpty(name)||null == handler){ return; } strategyMap.put(name,handler); } }
1.3 為各成員實現各自的具體策略實現類
將各自實現類聲明為組件(用於維護工廠),org.springframework.beans.factory.InitializingBean#afterPropertiesSet內部實現工廠注冊。
import org.springframework.stereotype.Component; /** * saobin策略實現*/ @Component public class SaoBinHandler implements NameHandler { /** * 輸出名稱 * @param name */ @Override public void myName(String name) { System.out.println("I am SaoBin"); } @Override public void afterPropertiesSet() throws Exception { NameSetFactory.register("saobin",this); } }
import org.springframework.stereotype.Component; /** * shaqiang策略實現*/ @Component public class ShaQiangHandler implements NameHandler { /** * 輸出名稱 * @param name */ @Override public void myName(String name) { System.out.println("I am ShaQiang"); } @Override public void afterPropertiesSet() throws Exception { NameSetFactory.register("shaqiang",this); } }
import org.springframework.stereotype.Component; /** * weifeng策略實現*/ @Component public class WeiFengHandler implements NameHandler { /** * 輸出名稱 * @param name */ @Override public void myName(String name) { System.out.println("I am WeiFeng"); } @Override public void afterPropertiesSet() throws Exception { NameSetFactory.register("weifeng",this); } }
1.4 新增if邏輯拓展
如上,如果后續再加新成員的業務,只需要實現其對應的具體策略類即可,不需要關注其對其他成員的業務是否有影響。
2. 策略模式+工廠模式+模板模式實現不同業務
現在來了新需求,之前成員實現的方法基本一致,但現在要求:“騷斌”實現打印名稱,“傻強”實現跳舞,“偉峰”實現打印名稱和跳舞,后續隨時會有新增成員和新增功能,基於上面的實現,可以在策略總接口中新增跳舞方法,實現如下:
可以看出,在總策略接口中新增“跳舞”方法后,沒有該功能的“騷斌”也需要實現它,這個就很不友好了。下面對其進行改造:
2.1 模板設計模式改造總策略接口
將原先的接口改造為抽象類,實現模板模式,所有的功能在類中定義,子類要實現具體功能,重寫即可。
import org.springframework.beans.factory.InitializingBean; /** * 策略抽象類(模板) */ public abstract class AbstractNameHandler implements InitializingBean { /** * 輸出名稱 * @param name */ public void myName(String name){ throw new UnsupportedOperationException(); }; /** * 跳舞 * @param name */ public void dance(String name){ throw new UnsupportedOperationException(); }; }
2.2 策略實現
各成員只需實現其對應的策略方法即可。
如下,測試成員功能,對於有具體實現的方法,成員會執行,如果沒有具體實現,會拋出異常。
經過上面改造,后面如果新增成員或者新功能實現,新增策略實現即可。這種改造符合開閉原則,適用較為復雜的邏輯判斷。