Java?設(shè)計(jì)模式中的策略模式詳情
策略模式的應(yīng)用場(chǎng)景
策略模式是否要使用,取決于業(yè)務(wù)場(chǎng)景是否符合,有沒(méi)有必要。
是否符合
如果業(yè)務(wù)是處于不同的場(chǎng)景時(shí),采取不同的處理方式的話(huà),就滿(mǎn)足符合。 這里舉幾個(gè)業(yè)務(wù)栗子
如果今天我有1000塊,那我就和朋友去游樂(lè)園玩、然后再去吃頓好吃的。如果有2000塊的話(huà),那我就先買(mǎi)一件好看的衣服,再和朋友去游樂(lè)園玩和吃好吃的商品收銀業(yè)務(wù),根據(jù)店中不同的活動(dòng)分為正常收費(fèi)、折扣收費(fèi)、返利收費(fèi),每種收費(fèi)的方式都不一樣接收某安全設(shè)備的數(shù)據(jù)的時(shí)候,根據(jù)發(fā)過(guò)來(lái)不同的數(shù)據(jù)類(lèi)型,執(zhí)行設(shè)備報(bào)警、設(shè)備指定信息存儲(chǔ)、設(shè)備本身狀態(tài)信息修改等等的處理方式
這里上面三種業(yè)務(wù)場(chǎng)景都符合處于不同的場(chǎng)景時(shí),采取不同的處理方式。
有沒(méi)有必要
這里等描述完例子后,再回到這個(gè)問(wèn)題
例子
這里采用上面第三個(gè)例子的業(yè)務(wù)分別進(jìn)行編寫(xiě)不用策略模式和用策略模式的效果
不用策略模式
public class Main {
public static void main(String[] args) {
//設(shè)備報(bào)警
int deviceDataType=2;
DeviceData deviceData=new DeviceData();
deviceData.setName("安全設(shè)備A");
switch (deviceDataType){
case 1:
DeviceCallPolice(deviceData);
break;
case 2:
DeviceStatus(deviceData);
break;
default:
System.out.println("沒(méi)有相關(guān)的策略");
break;
}
}
private static void DeviceStatus(DeviceData deviceData) {
System.out.println("正在修改"+deviceData.getName()+"狀態(tài)為指定狀態(tài)");
System.out.println("正在記錄本次修改狀態(tài)的時(shí)間信息");
System.out.println("根據(jù)修改后的狀態(tài)判斷是否要通知相關(guān)人");
}
private static void DeviceCallPolice(DeviceData deviceData) {
System.out.println("正在修改"+deviceData.getName()+"狀態(tài)為報(bào)警狀態(tài)");
System.out.println("正在記錄本次報(bào)警時(shí)間信息");
System.out.println("設(shè)備相關(guān)人的短信通知");
}
}效果:

使用策略模式

策略上下文
/**
*
* 安全設(shè)備處理上下文
*/
public class SafetyDeviceContext {
private DeviceHandlerStrategy deviceHandlerStrategy;
public SafetyDeviceContext(int dataType){
switch (dataType){
case 1:
deviceHandlerStrategy=new DeviceCallPoliceStrategy();
break;
case 2:
deviceHandlerStrategy=new DeviceStatusStrategy();
break;
default:
System.out.println("沒(méi)有相關(guān)的策略");
break;
}
}
public void Handler(DeviceData deviceData){
deviceHandlerStrategy.handler(deviceData);
}
}策略接口以及具體實(shí)現(xiàn)類(lèi)
/**
* 設(shè)備處理策略
*/
public interface DeviceHandlerStrategy {
void handler(DeviceData deviceData);
}/**
* 安全設(shè)備報(bào)警策略
*/
public class DeviceCallPoliceStrategy implements DeviceHandlerStrategy {
@Override
public void handler(DeviceData deviceData) {
System.out.println("正在修改設(shè)備狀態(tài)為報(bào)警狀態(tài)");
System.out.println("正在記錄本次報(bào)警時(shí)間信息");
System.out.println("設(shè)備相關(guān)人的短信通知");
}
}/**
* 設(shè)備狀態(tài)修改策略
*/
public class DeviceStatusStrategy implements DeviceHandlerStrategy {
@Override
public void handler(DeviceData deviceData) {
System.out.println("正在修改設(shè)備狀態(tài)為指定狀態(tài)");
System.out.println("正在記錄本次修改狀態(tài)的時(shí)間信息");
System.out.println("根據(jù)修改后的狀態(tài)判斷是否要通知相關(guān)人");
}
}Main類(lèi)
public class Main {
public static void main(String[] args) {
//設(shè)備報(bào)警
int deviceDataType=2;
DeviceData deviceData=new DeviceData();
deviceData.setName("安全設(shè)備A");
SafetyDeviceContext safetyDeviceContext=new SafetyDeviceContext(deviceDataType);
safetyDeviceContext.handler(deviceData);
}
}效果:

兩種方式的不同
從簡(jiǎn)易和易懂程度來(lái)說(shuō),自然是不用策略模式好一些,用策略模式會(huì)導(dǎo)致類(lèi)的增多,而且如果不懂策略模式的人去看代碼時(shí)可讀性不高。但使用策略模式勝于可擴(kuò)展性和可維護(hù)性要強(qiáng)于不用策略模式的
使用策略模式在Main函數(shù)(使用方),消除了類(lèi)型的swich判斷,把這些判斷放到了Context,使用方調(diào)用的時(shí)候,就不必過(guò)多關(guān)心設(shè)備處理策略,只需要把值傳進(jìn)Context就好了。
之前我很不理解策略模式為什么能避免使用多重條件判斷,因?yàn)樯厦娴膶?xiě)法只是把判斷的代碼移到了Context而已,要寫(xiě)的判斷還是要寫(xiě),直到我知道了采用字典和反射的方式時(shí),就理解了,往下會(huì)說(shuō)
- 如果后續(xù)我們要添加一種"設(shè)備定時(shí)報(bào)告信息"業(yè)務(wù)處理方式時(shí),使用策略模式那種只需要在Context添加一層case(也可以不需要,可以用反射的方式)和添加一個(gè)策略的實(shí)現(xiàn)類(lèi)就好了,而不用策略模式需要在原來(lái)使用方的代碼添加一層case,可能會(huì)影響到原來(lái)的業(yè)務(wù)穩(wěn)定性。
- 算法獨(dú)立出來(lái)也方便我們使用單元測(cè)試進(jìn)行測(cè)試
策略模式有沒(méi)有必要使用?
策略模式的目的是減少具體的算法方式和使用方式之間的耦合,避免多重if判斷,并讓具體的算法方法盡可能獨(dú)立。所以實(shí)現(xiàn)的時(shí)候,必然成本會(huì)高一些。因此我們要使用策略模式的時(shí)候,要確定該業(yè)務(wù)業(yè)務(wù)本身是否復(fù)雜,后續(xù)是不是會(huì)時(shí)不時(shí)添加其他的處理方式。
例如上面的第三個(gè)例子,設(shè)備對(duì)應(yīng)的處理措施本身具備了復(fù)雜性,例如會(huì)涉及數(shù)據(jù)本身的處理、設(shè)備狀態(tài)的更改、設(shè)備事件的觸發(fā)等等處理措施,而且后續(xù)因業(yè)務(wù)的擴(kuò)展,可能會(huì)添加不同的設(shè)備場(chǎng)景,不同的設(shè)備處理方式。像這種就可以考慮使用
如何避免Context類(lèi)使用判斷邏輯
可以采用字典+反射的方式進(jìn)行避免
定義策略字典的全局變量
/**
* 設(shè)備處理策略方式字典
*/
public class DeviceStrategyDictionary {
public static HashMap<Integer,String> dictionary=new HashMap<>();
}修改Context的代碼
import java.util.HashMap;
/**
* 安全設(shè)備處理上下文
*/
public class SafetyDeviceContext {
private DeviceHandlerStrategy deviceHandlerStrategy;
public SafetyDeviceContext(int dataType) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
HashMap<Integer,String> dic= DeviceStrategyDictionary.dictionary;
if(!dic.containsKey(dataType)){
System.out.println("不包含該處理方式");
}
//使用反射的方式
Class<?> fz=Class.forName(dic.get(dataType));
deviceHandlerStrategy=(DeviceHandlerStrategy) fz.newInstance();
}
public void handler(DeviceData deviceData){
deviceHandlerStrategy.handler(deviceData);
}
}Main方法
public class Main {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//程序啟動(dòng)的時(shí)候
DeviceStrategyDictionary.dictionary.put(1,"DeviceCallPoliceStrategy");
DeviceStrategyDictionary.dictionary.put(2,"DeviceStatusStrategy");
//設(shè)備報(bào)警
int deviceDataType=2;
DeviceData deviceData=new DeviceData();
deviceData.setName("安全設(shè)備A");
SafetyDeviceContext safetyDeviceContext=new SafetyDeviceContext(deviceDataType);
safetyDeviceContext.handler(deviceData);
}
}效果:

這樣就可以避免使用if判斷了,不過(guò)反射也有相關(guān)的性能消耗,這點(diǎn)也需要做權(quán)衡。
到此這篇關(guān)于Java 設(shè)計(jì)模式中的策略模式詳情的文章就介紹到這了,更多相關(guān)Java 策略模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解JVM類(lèi)加載機(jī)制及類(lèi)緩存問(wèn)題的處理方法
這篇文章主要給大家介紹了關(guān)于JVM類(lèi)加載機(jī)制及類(lèi)緩存問(wèn)題的處理方法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01
MyBatis常用標(biāo)簽以及使用技巧總結(jié)
在我們的學(xué)習(xí)過(guò)程中,我們經(jīng)常使用到mybatis,這篇文章主要給大家介紹了關(guān)于MyBatis常用標(biāo)簽以及使用技巧的相關(guān)資料,需要的朋友可以參考下2021-05-05
詳解Spring Boot工程集成全局唯一ID生成器 UidGenerator的操作步驟
本文就在項(xiàng)目中來(lái)集成 UidGenerator這一工程來(lái)作為項(xiàng)目的全局唯一 ID生成器。接下來(lái)通過(guò)實(shí)例代碼給大家詳解詳解Spring Boot工程集成全局唯一ID生成器 UidGenerator的操作步驟,感興趣的朋友一起看看吧2018-10-10
探索Java中private方法添加@Transactional事務(wù)未生效原因
你又遇到過(guò)明明給private方法添加了@Transactional但是事務(wù)依然沒(méi)有生效的情況嗎,具體原因本篇文章將詳細(xì)告訴你,有需要的朋友跟著小編往下看吧2021-11-11
springSecurity用戶(hù)認(rèn)證和授權(quán)的實(shí)現(xiàn)
Spring?Security?是一個(gè)開(kāi)源的安全框架,提供了基于權(quán)限的訪問(wèn)控制、身份認(rèn)證的功能,本文主要介紹了springSecurity用戶(hù)認(rèn)證和授權(quán),具有一定參考價(jià)值,感興趣的可以了解一下2024-04-04
mybatis-plus添加數(shù)據(jù)時(shí)id自增問(wèn)題及解決
這篇文章主要介紹了mybatis-plus添加數(shù)據(jù)時(shí)id自增問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
運(yùn)行Jar包出現(xiàn)提示xxx中沒(méi)有主清單屬性報(bào)錯(cuò)問(wèn)題解決方法
這篇文章主要介紹了運(yùn)行Jar包出現(xiàn):xxx中沒(méi)有主清單屬性報(bào)錯(cuò),當(dāng)出現(xiàn)報(bào)錯(cuò):xxx中沒(méi)有主清單屬性,解決方法也很簡(jiǎn)單,在pom.xml配置中,加上相應(yīng)配置即可,需要的朋友可以參考下2023-08-08

