Java?策略模式?if-else用法實例詳解
引言:
公司要擴(kuò)大規(guī)模,目前需要購買一批汽車,還要招聘一批保安,老板指示暫時只想看新車,只需要給他看按照價格排好序的新車列表就行;保安候選人按照安保工作經(jīng)驗排好序給他一個列表。
汽車數(shù)據(jù),還有保安候選人的數(shù)據(jù)已經(jīng)放在了程序員的面前,你只需要給我個列表就好了。
基于這個需求,我們自然而然的會想到排序啊。
開始之前,我們先來看一下jdk中的comparable接口
和comparator接口
,可參考 文檔描述
策略模式
comparable接口
java.lang Interface Comparable
T - the type of objects that this object may be compared to(可以與之比較的對象的類型)
需要實現(xiàn)的方法:
int compareTo(T o)
參數(shù):
o - 要比較的對象
返回:
當(dāng)此對象小于指定的對象時返回負(fù)整數(shù),等于返回0,大于返回正整數(shù)
我們寫Car
類和SecurityMan
類,讓他們都實現(xiàn)Comparable
接口
汽車按價格排序:
public class Car implements Comparable<Car> { //價格 private int price; //油箱容量 private int capacity; public Car(int price, int capacity) { this.price = price; this.capacity = capacity; } @Override public int compareTo(Car c) { if (this.price < c.price) { return -1; } if (this.price > c.price) { return 1; } return 0; } @Override public String toString() { return "Car{" + "price=" + price + ", capacity=" + capacity + '}'; } }
保安按工作經(jīng)驗排序:
public class SecurityMan implements Comparable<SecurityMan> { //安保經(jīng)驗 private int experience; //顏值 private int beauty; public SecurityMan(int experience, int beauty) { this.experience = experience; this.beauty = beauty; } @Override public int compareTo(SecurityMan o) { if (this.experience < o.experience) { return -1; } if (this.experience > o.experience) { return 1; } return 0; } @Override public String toString() { return "SecurityMan{" + "experience=" + experience + ", beauty=" + beauty + '}'; } }
再來一個Context
類,來封裝對那些對象進(jìn)行比較的類
public class Context { public void sortCar(Car[] cars) { for (int i = 0; i < cars.length; i++) { int minIndex = i; for (int j = i + 1; j < cars.length; j++) { minIndex = cars[i].compareTo(cars[j]) > 0 ? j : minIndex; } Car c = cars[i]; cars[i] = cars[minIndex]; cars[minIndex] = c; } } public void sortSecurityMan(SecurityMan[] men) { for (int i = 0; i < men.length; i++) { int minIndex = i; for (int j = i + 1; j < men.length; j++) { minIndex = men[i].compareTo(men[j]) > 0 ? j : minIndex; } SecurityMan c = men[i]; men[i] = men[minIndex]; men[minIndex] = c; } } }
那么問題來了,如果老板想要看汽車容量排序怎么辦?要看保安顏值排序怎么辦?
對于Car
類,我們可以加一個屬性,比如sortBy
,在compareTo
方法中加if-else
,根據(jù)sortBy
的值進(jìn)行不同的排序,而且Context
類中也要加對應(yīng)的方法。
這樣的話,后續(xù)如果你加更多的排序,就需要修改多處代碼,這酸爽。。。我如果想要對一個對象進(jìn)行比較的策略能夠靈活的指定,這才是最好的!??!
comparator接口
java.util Interface Comparator
T - the type of objects that may be compared by this comparator(比較器可以比較的對象類型)
方法:
int compare(T o1, T o2)
參數(shù):
o1 - 第一個需要排序的對象
o2 - 第二個需要排序的對象
返回:
第一個需要排序的對象如果小于、等于、大于第二個對象,返回負(fù)整數(shù),0,正整數(shù)
不同的排序策略實現(xiàn)
我們用Comparator
接口來實現(xiàn)各種排序策略。
策略1:對汽車按照價格排序
public class CarPriceComparator implements Comparator<Car> { @Override public int compare(Car o1, Car o2) { if (o1.price < o2.price) return -1; else if (o1.price > o2.price) return 1; return 0; } }
策略2:對汽車按照容量排序
public class CarCapacityComparator implements Comparator<Car> { @Override public int compare(Car o1, Car o2) { if (o1.capacity > o2.capacity) return -1; else if (o1.capacity < o2.capacity) return 1; return 0; } }
策略3:對保安按照工作經(jīng)驗排序
public class SecurityManExperienceComparator implements Comparator<SecurityMan> { @Override public int compare(SecurityMan o1, SecurityMan o2) { if (o1.experience < o2.experience) return -1; else if (o1.experience > o2.experience) return 1; return 0; } }
策略4:對保安按照顏值排序
public class SecurityManBeautyComparator implements Comparator<SecurityMan> { @Override public int compare(SecurityMan o1, SecurityMan o2) { if (o1.beauty < o2.beauty) return -1; else if (o1.beauty > o2.beauty) return 1; return 0; } }
這時我們的Context
就可以為所欲為了,你想要對誰排序就可以對誰排序,只要你有相應(yīng)的排序策略就可以。
Context策略切換上下文:
public class Context<T> { private Comparator comparator; public Context(Comparator comparator) { this.comparator = comparator; } public void sortWhatYouWant(T[] arr) { for (int i = 0; i < arr.length; i++) { int minIndex = i; for (int j = i + 1; j < arr.length; j++) { minIndex = this.comparator.compare(arr[i], arr[j]) > 0 ? j : minIndex; } T o = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = o; } } }
Client
-相當(dāng)于老板,老板想要什么排序策略,直接調(diào)起Context
切換策略:
public class Client { public static void main(String[] args) { Car[] cars = {new Car(18, 55), new Car(12, 40), new Car(25, 60)}; SecurityMan[] men = {new SecurityMan(10, 95), new SecurityMan(6, 92), new SecurityMan(8, 97)}; // Context ctx = new Context(new CarCapacityComparator()); Context ctx = new Context(new SecurityManBeautyComparator()); ctx.sortWhatYouWant(men); System.out.println(Arrays.toString(men)); } }
這種寫法是不是比if-else
逼格高了一些呢,^_^
這其實就是策略模式
,他很好滴踐行了 對修改關(guān)閉,對擴(kuò)展開放
的設(shè)計原則。
總結(jié)一下,我們上面實現(xiàn)的策略模式類圖:
策略模式比if-else香在哪呢?有缺點(diǎn)嗎?
執(zhí)行方式可以自由切換:
比如我們上面舉的例子,可以對排序策略進(jìn)行自由的切換。
執(zhí)行方式可以自由切換
是策略模式本身定義的,只要實現(xiàn)抽象策略,它就成為策略家族的一個成員,通過封裝角色對其進(jìn)行封裝,保證對外提供“可自由切換”的策略
避免使用多重條件判斷:
就我們的例子而言,兩個類,每個類都有可排序的兩個屬性,如果分別按照各自的屬性排序,得寫多少
if-else
?。。?!
擴(kuò)展性良好:
擴(kuò)展性當(dāng)然良好。一個具體的策略很好實現(xiàn)啊。
缺點(diǎn)其實顯而易見:
- 1.策略類數(shù)量增多
每一個策略都是一個類,復(fù)用的可能性很小,類數(shù)量增多。
- 2.所有的策略類都需要對外暴露
每有一個策略,都得告訴別人一下,否則老板也不知道你能不能給我滿足我的要求。
也就是說上層模塊必須知道有哪些策略,然后才能決定使用哪一個策略,那么我只是想使用了一個策略,我憑什么就要了解這個策略呢?那要你的封裝類還有什么意義?
策略模式有哪些使用場景呢?
- 多個類只有在算法或行為上稍有不同的場景
- 算法需要自由切換的場景
例如,算法的選擇是由使用者決定的,或者算法始終在進(jìn)化,特別是一些站在技術(shù)前沿的行業(yè),連業(yè)務(wù)專家都無法給你保證這樣的系統(tǒng)規(guī)則能夠存在多長時間,在這種情況下策略模式是你最好的助手。
- 需要屏蔽算法規(guī)則的場景
現(xiàn)在的科技發(fā)展得很快,人腦的記憶是有限的(就目前來說是有限的),太多的算法你只要知道一個名字就可以了,傳遞相關(guān)的數(shù)字進(jìn)來,反饋一個運(yùn)算結(jié)果,萬事大吉。
有N多個策略怎么辦?
如果系統(tǒng)中的一個策略家族的具體策略數(shù)量超過4個,則需要考慮使用混合模式,解決策略類膨脹和對外暴露的問題,否則日后的系統(tǒng)維護(hù)就會成為一個燙手山芋,誰都不想接。
針對策略模式的缺點(diǎn),我們可以使用其他模式來修正這個缺陷,如工廠方法模式、代理模式或享元模式等。
總結(jié)
到此這篇關(guān)于Java 策略模式 if-else用法詳解的文章就介紹到這了,更多相關(guān)Java if-else內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用反射實現(xiàn)Excel和CSV 轉(zhuǎn)換為Java對象功能
將Excel或CSV文件轉(zhuǎn)換為Java對象(POJO)以及將Java對象轉(zhuǎn)換為Excel或CSV文件可能是一個復(fù)雜的過程,但如果使用正確的工具和技術(shù),這個過程就會變得十分簡單,在本文中,我們將了解如何利用一個Java反射的庫來實現(xiàn)這個功能,需要的朋友可以參考下2023-11-11Spring Boot 集成Mybatis實現(xiàn)主從(多數(shù)據(jù)源)分離方案示例
本篇文章主要介紹了Spring Boot 集成Mybatis實現(xiàn)主從(多數(shù)據(jù)源)分離方案實例,具有一定的參考價值,有興趣的可以了解一下。2017-03-03解決IDEA集成Docker插件后出現(xiàn)日志亂碼的問題
這篇文章主要介紹了解決IDEA集成Docker插件后出現(xiàn)日志亂碼的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11java實現(xiàn)文件和base64相互轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了java如何實現(xiàn)文件和base64相互轉(zhuǎn)換,文中的示例代碼講解詳細(xì),具有一定的參考價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11java正則表達(dá)式實現(xiàn)提取需要的字符并放入數(shù)組【ArrayList數(shù)組去重復(fù)功能】
這篇文章主要介紹了java正則表達(dá)式實現(xiàn)提取需要的字符并放入數(shù)組,即基于正則的ArrayList數(shù)組去重復(fù)功能,具有一定參考借鑒價值,需要的朋友可以參考下2017-01-01