Java?策略模式?if-else用法實(shí)例詳解
引言:
公司要擴(kuò)大規(guī)模,目前需要購(gòu)買(mǎi)一批汽車,還要招聘一批保安,老板指示暫時(shí)只想看新車,只需要給他看按照價(jià)格排好序的新車列表就行;保安候選人按照安保工作經(jīng)驗(yàn)排好序給他一個(gè)列表。
汽車數(shù)據(jù),還有保安候選人的數(shù)據(jù)已經(jīng)放在了程序員的面前,你只需要給我個(gè)列表就好了。
基于這個(gè)需求,我們自然而然的會(huì)想到排序啊。
開(kāi)始之前,我們先來(lái)看一下jdk中的comparable接口和comparator接口,可參考 文檔描述
策略模式
comparable接口
java.lang Interface Comparable
T - the type of objects that this object may be compared to(可以與之比較的對(duì)象的類型)
需要實(shí)現(xiàn)的方法:
int compareTo(T o)
參數(shù):
o - 要比較的對(duì)象
返回:
當(dāng)此對(duì)象小于指定的對(duì)象時(shí)返回負(fù)整數(shù),等于返回0,大于返回正整數(shù)
我們寫(xiě)Car類和SecurityMan類,讓他們都實(shí)現(xiàn)Comparable接口
汽車按價(jià)格排序:
public class Car implements Comparable<Car> {
//價(jià)格
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)驗(yàn)排序:
public class SecurityMan implements Comparable<SecurityMan> {
//安保經(jīng)驗(yàn)
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 +
'}';
}
}再來(lái)一個(gè)Context類,來(lái)封裝對(duì)那些對(duì)象進(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;
}
}
}那么問(wèn)題來(lái)了,如果老板想要看汽車容量排序怎么辦?要看保安顏值排序怎么辦?
對(duì)于Car類,我們可以加一個(gè)屬性,比如sortBy,在compareTo方法中加if-else,根據(jù)sortBy的值進(jìn)行不同的排序,而且Context類中也要加對(duì)應(yīng)的方法。
這樣的話,后續(xù)如果你加更多的排序,就需要修改多處代碼,這酸爽。。。我如果想要對(duì)一個(gè)對(duì)象進(jìn)行比較的策略能夠靈活的指定,這才是最好的?。?!
comparator接口
java.util Interface Comparator
T - the type of objects that may be compared by this comparator(比較器可以比較的對(duì)象類型)
方法:
int compare(T o1, T o2)
參數(shù):
o1 - 第一個(gè)需要排序的對(duì)象
o2 - 第二個(gè)需要排序的對(duì)象
返回:
第一個(gè)需要排序的對(duì)象如果小于、等于、大于第二個(gè)對(duì)象,返回負(fù)整數(shù),0,正整數(shù)
不同的排序策略實(shí)現(xiàn)
我們用Comparator接口來(lái)實(shí)現(xiàn)各種排序策略。
策略1:對(duì)汽車按照價(jià)格排序
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:對(duì)汽車按照容量排序
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:對(duì)保安按照工作經(jīng)驗(yàn)排序
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:對(duì)保安按照顏值排序
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;
}
}這時(shí)我們的Context就可以為所欲為了,你想要對(duì)誰(shuí)排序就可以對(duì)誰(shuí)排序,只要你有相應(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));
}
}這種寫(xiě)法是不是比if-else逼格高了一些呢,^_^
這其實(shí)就是策略模式,他很好滴踐行了 對(duì)修改關(guān)閉,對(duì)擴(kuò)展開(kāi)放的設(shè)計(jì)原則。
總結(jié)一下,我們上面實(shí)現(xiàn)的策略模式類圖:

策略模式比if-else香在哪呢?有缺點(diǎn)嗎?
執(zhí)行方式可以自由切換:
比如我們上面舉的例子,可以對(duì)排序策略進(jìn)行自由的切換。
執(zhí)行方式可以自由切換是策略模式本身定義的,只要實(shí)現(xiàn)抽象策略,它就成為策略家族的一個(gè)成員,通過(guò)封裝角色對(duì)其進(jìn)行封裝,保證對(duì)外提供“可自由切換”的策略
避免使用多重條件判斷:
就我們的例子而言,兩個(gè)類,每個(gè)類都有可排序的兩個(gè)屬性,如果分別按照各自的屬性排序,得寫(xiě)多少
if-else?。。?!
擴(kuò)展性良好:
擴(kuò)展性當(dāng)然良好。一個(gè)具體的策略很好實(shí)現(xiàn)啊。
缺點(diǎn)其實(shí)顯而易見(jiàn):
- 1.策略類數(shù)量增多
每一個(gè)策略都是一個(gè)類,復(fù)用的可能性很小,類數(shù)量增多。
- 2.所有的策略類都需要對(duì)外暴露
每有一個(gè)策略,都得告訴別人一下,否則老板也不知道你能不能給我滿足我的要求。
也就是說(shuō)上層模塊必須知道有哪些策略,然后才能決定使用哪一個(gè)策略,那么我只是想使用了一個(gè)策略,我憑什么就要了解這個(gè)策略呢?那要你的封裝類還有什么意義?
策略模式有哪些使用場(chǎng)景呢?
- 多個(gè)類只有在算法或行為上稍有不同的場(chǎng)景
- 算法需要自由切換的場(chǎng)景
例如,算法的選擇是由使用者決定的,或者算法始終在進(jìn)化,特別是一些站在技術(shù)前沿的行業(yè),連業(yè)務(wù)專家都無(wú)法給你保證這樣的系統(tǒng)規(guī)則能夠存在多長(zhǎng)時(shí)間,在這種情況下策略模式是你最好的助手。
- 需要屏蔽算法規(guī)則的場(chǎng)景
現(xiàn)在的科技發(fā)展得很快,人腦的記憶是有限的(就目前來(lái)說(shuō)是有限的),太多的算法你只要知道一個(gè)名字就可以了,傳遞相關(guān)的數(shù)字進(jìn)來(lái),反饋一個(gè)運(yùn)算結(jié)果,萬(wàn)事大吉。
有N多個(gè)策略怎么辦?
如果系統(tǒng)中的一個(gè)策略家族的具體策略數(shù)量超過(guò)4個(gè),則需要考慮使用混合模式,解決策略類膨脹和對(duì)外暴露的問(wèn)題,否則日后的系統(tǒng)維護(hù)就會(huì)成為一個(gè)燙手山芋,誰(shuí)都不想接。
針對(duì)策略模式的缺點(diǎn),我們可以使用其他模式來(lái)修正這個(gè)缺陷,如工廠方法模式、代理模式或享元模式等。
總結(jié)
到此這篇關(guān)于Java 策略模式 if-else用法詳解的文章就介紹到這了,更多相關(guān)Java if-else內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決 IDEA 創(chuàng)建 Gradle 項(xiàng)目沒(méi)有src目錄問(wèn)題
這篇文章主要介紹了解決 IDEA 創(chuàng)建 Gradle 項(xiàng)目沒(méi)有src目錄問(wèn)題,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06
mybatis單筆批量保存實(shí)體數(shù)據(jù)的方法
這篇文章主要介紹了mybatis單筆批量保存實(shí)體數(shù)據(jù)的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-01-01
手把手教你使用Java實(shí)現(xiàn)在線生成pdf文檔
在實(shí)際的業(yè)務(wù)開(kāi)發(fā)的時(shí)候,常常會(huì)需要把相關(guān)的數(shù)據(jù)信息,通過(guò)一些技術(shù)手段生成對(duì)應(yīng)的PDF文件,然后返回給用戶。本文將手把手教大家如何利用Java實(shí)現(xiàn)在線生成pdf文檔,需要的可以參考一下2022-03-03
Java Kafka實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列的示例詳解
在分布式系統(tǒng)中,消息隊(duì)列是一種常見(jiàn)的異步通信機(jī)制,而優(yōu)先級(jí)隊(duì)列則是消息隊(duì)列的一種特殊形式,下面我們來(lái)看看如何利用Kafka實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列吧2025-03-03
Spring?Boot簡(jiǎn)單實(shí)現(xiàn)文件上傳功能
這篇文章主要介紹了Spring?Boot簡(jiǎn)單實(shí)現(xiàn)文件上傳功能,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08

