作者 l 南山獅
來源 l Hollis(ID:hollischuang)
我也不用設計模式
很多人覺得自己寫的是業(yè)務代碼等脂,按照邏輯寫下去,再把公用的方法抽出來復用就可以了撑蚌,設計模式根本就沒必要用上遥,更沒必要學。
一開始的時候争涌,我也是這么想粉楚,直到我遇到。亮垫。模软。
舉個栗子
我們先看一個普通的下單攔截接口。
基本邏輯饮潦,參數(shù)安全攔截燃异,次數(shù)攔截,規(guī)則攔截继蜡,都通過回俐,返回允許下單,任意一個失敗稀并,返回對應的失敗原因仅颇。
多層嵌套if寫法
我們正常多層嵌套if的寫法
/**
* @author saier
* @date 2020/3/31 18:03
*/
public class Order {
public Message interrupt1(){
return null;
}
public Message interrupt2(){
return null;
}
public Message interrupt3(){
return null;
}
public Message interrupt4(){
return null;
}
public Message interrupt5(){
return null;
}
public static void main(String[] args) {
Order order= new Order();
if(order.interrupt1().getResult() == 1){
if(order.interrupt2().getResult() == 1){
if(order.interrupt3().getResult() == 1){
if(order.interrupt4().getResult() == 1){
if(order.interrupt5().getResult() == 1){
System.out.println("success");
}
}
}
}
}
}
}
@Data
class Message {
private int result;
private String msg;
}
異常處理邏輯
或者有些利用異常做邏輯,代碼會簡單一點
/**
* @author saier
* @date 2020/3/31 18:03
*/
public class Order2 {
public void interrupt1(){
}
public void interrupt2(){
}
public void interrupt3(){
//失敗
throw new RuntimeException();
}
public void interrupt4(){
//失敗
throw new RuntimeException();
}
public void interrupt5(){
//失敗
throw new RuntimeException();
}
public static void main(String[] args) {
Order2 order2= new Order2();
try{
order2.interrupt1();
order2.interrupt2();
order2.interrupt3();
order2.interrupt4();
order2.interrupt5();
System.out.println("success");
}catch (RuntimeException e){
System.out.println("fail");
}
}
}
一開始碘举,我就直接使用異常來做邏輯忘瓦。但后續(xù)邏輯越來越復雜之后,也會出現(xiàn)一些問題引颈。例如異常只能返回異常信息耕皮,不能返回更多的字段信息境蜕。
后面也留意到,異常做邏輯凌停,在阿里規(guī)范是禁止的汽摹。
阿里代碼規(guī)范 :
【強制】異常不要用來做流程控制,條件控制苦锨。
說明:異常設計的初衷是解決程序運行中的各種意外情況,且異常的處理效率比條件判斷方式要低很多趴泌。
更重要的是舟舒,代碼可讀性太差了,隨時一個方法的異常拋出來嗜憔,還要考慮代碼本身的異常秃励。
沒更好的辦法,只能考慮設計模式了
怎么改吉捶,會使代碼的可讀性高夺鲜,擴展性好?
在同事的提醒下呐舔,突然想起了設計模式币励!
我們希望達到的目的
代碼沒有這么多if else嵌套,可讀性高
如果新增新的攔截邏輯簡單方便珊拼,不影響原本的邏輯食呻,擴展性好
可以很方便地調換攔截邏輯順序,低耦合
責任鏈模式
在這種場景下澎现,非常適合責任鏈模式仅胞。(什么場景使用什么設計模式,這就需要平時有積累剑辫,知道各種設計模式的基本使用)
責任鏈干旧,顧名思義,就是用來處理相關事務責任的一條執(zhí)行鏈妹蔽,執(zhí)行鏈上有多個節(jié)點椎眯,每個節(jié)點都有機會(條件匹配)處理請求事務,如果某個節(jié)點處理完了就可以根據(jù)實際業(yè)務需求傳遞給下一個節(jié)點繼續(xù)處理或者返回處理完畢讹开。
首先盅视,建立過濾器的抽象類
public abstract class AbstractFilter {
private AbstractFilter nextFilter;
/**
* 責任鏈的下一個元素
*/
public void setNextFilter(AbstractFilter nextFilter){
this.nextFilter = nextFilter;
}
public AbstractFilter getLastFilter(){
if(this.nextFilter != null){
return this.nextFilter.getLastFilter();
}else{
return this;
}
}
public void filter(FilterRequest filterRequest, Response response){
doFilter(filterRequest,response);
if(response.isFilterNext() && nextFilter != null){
nextFilter.filter(filterRequest,response);
}
}
/**
* 具體攔截邏輯
*/
public abstract void doFilter(FilterRequest filterRequest, Response response);
/**
* 根據(jù)攔截結果做處理
*/
public void exec(FilterRequest filterRequest, Response response){
}
}
過濾器的實現(xiàn)類
@Component
@Order(5)
public class CheckParamFilter1 extends AbstractFilter {
@Override
public void doFilter(FilterRequest filterRequest, Response response) {
}
}
@Component
@Order(10)
public class CheckParamFilter2 extends AbstractFilter {
@Override
public void doFilter(FilterRequest filterRequest, Response response) {
}
}
使用Order注解,確定過濾器的順序旦万,后續(xù)在spring注入的時候闹击,會有奇效
//利用spring的自動注入機制
@Autowired
List<AbstractFilter> abstractFilterList;
private AbstractFilter firstFilter;
//spring注入后自動執(zhí)行
@PostConstruct
public void initializeChainFilter(){
//把所有調用的邏輯注入到責任鏈,按照Order排序成艘,越小優(yōu)先級越高
for(int i = 0;i<abstractFilterList.size();i++){
if(i == 0){
firstFilter = abstractFilterList.get(i);
}else{
firstFilter.getLastFilter().setNextFilter(abstractFilterList.get(i));
}
}
}
//直接使用
public Response exec(){
firstFilter.filter(filterRequest, response);
return response;
}
使用設計模式的好處
看下使用責任鏈模式后赏半,有什么好處贺归!
新增攔截邏輯,只需要再實現(xiàn)一個AbstractFilter類即可
修改攔截順序断箫,只需要修改Order注解的大小拂酣,越小,優(yōu)先級越高
代碼清晰仲义,所有處理邏輯下沉到實現(xiàn)類中
使用設計模式的缺點
做到了低耦合婶熬,高擴展。但也帶來了一些不好的地方
邏輯更復雜埃撵,用了鏈式等數(shù)據(jù)結構赵颅,要注意單例的問題,不能重復使用
類數(shù)量激增暂刘,一個攔截器就一個類
最后小結一下
不是什么地方都適合使用設計模式饺谬,如果邏輯簡單,你硬要使用設計模式谣拣,只會帶來結構上的復雜募寨,大家可以按照大家的業(yè)務場景來使用。