設(shè)計(jì)模式之職責(zé)鏈模式

在業(yè)務(wù)開發(fā)中,為了處理某個屬性,可能需要復(fù)雜的處理邏輯,才能得到,一般的做法是按步驟處理,最終得到想要的結(jié)果。作者的業(yè)務(wù)場景為計(jì)算用戶的年化收益率,這個年化收益率是根據(jù)用戶的行為計(jì)算而來。目前項(xiàng)目中的代碼是按常規(guī)步驟處理,代碼非?;靵y,今天重新看一下代碼,覺得可以使用職責(zé)鏈模式來解決。

業(yè)務(wù)場景:

產(chǎn)品為一款WIFI連接APP,類似萬能鑰匙之類的,并有理財(cái)功能,理財(cái)?shù)哪昊找媛适歉鶕?jù)用戶的行為計(jì)算而來,用戶打開理財(cái)頁面的時候,根據(jù)用戶前一天的行為計(jì)算年化收益率

用戶行為:

這里只列出以下幾種,實(shí)際情況更加復(fù)雜,種類跟多

1.是否為vip
2.是否分享過wifi
3.是否使用過連接wifi
4.通過連接wifi使用的流量,流量使用越多,加息越多
5.是否支付1元,購買加息

當(dāng)前的處理邏輯

double totalYield = 0.04;//某基金基礎(chǔ)年化收益率
int vipCode = getUserVipCode();
if(vipCode.equlas("100")){
  totalYield = totalYiedl+0.02;//如果是vip,就增加0.02
}
boolean wifiConnect = getWifiConnect();
if(wifiConnect){
  totalYield = totalYiedl+0.01;//如果連接過wifi,就增加0.01
}
//如果分享過wifi,就增加0.01
//如果...,就增加...
...
return totalYield;

這里只是偽代碼,實(shí)際項(xiàng)目中有好幾百行,如果算上調(diào)用其他service層的代碼,估計(jì)有上千行代碼,
接下來,作者使用職責(zé)鏈模式來重構(gòu)一下這個業(yè)務(wù)邏輯代碼。

類圖

年化收益率類圖.JPG
  • UserActive 用戶行為
  • YeildCaculatorHandler 抽象類年化收益率計(jì)算器
  • YeildCaculatorOfVip vip年化收益率計(jì)算器
  • YeildCaculatorOfFlow 流量使用年化收益率計(jì)算器
  • YeildCaculatorOfOneYuan 購買一元加息年化收益率計(jì)算器
  • YeildCaculatorOfShare 分享WIFI年化收益率計(jì)算器
  • YeildCaculatorOfWifiConnect WIFI連接年化收益率計(jì)算器

UserActivie

package com.charlie.wifi.yeild;

public class UserActive {

    private String userName;
    private int vipCode;
    private boolean oneYuan;
    private boolean wifiConnect;
    private int flow;
    private boolean share;
    private double totalYeild = 0.04;

    public UserActive(String userName, int vipCode, boolean oneYuan, boolean wifiConnect, int flow, boolean share) {
        super();
        this.userName = userName;
        this.vipCode = vipCode;
        this.oneYuan = oneYuan;
        this.wifiConnect = wifiConnect;
        this.flow = flow;
        this.share = share;
    }
//省略get set

YeildCaculatorHandler

package com.charlie.wifi.yeild;

public abstract class YeildCaculatorHandler {

    protected String name;

    protected YeildCaculatorHandler successor;

    public YeildCaculatorHandler(String name) {
        super();
        this.name = name;
    }

    public void setSuccessor(YeildCaculatorHandler successor) {
        this.successor = successor;
    }

    public abstract double caculator(UserActive userActive);

}

YeildCaculatorOfFlow

package com.charlie.wifi.yeild;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class YeildCaculatorOfFlow extends YeildCaculatorHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public YeildCaculatorOfFlow(String name) {
        super(name);
    }

    @Override
    public double caculator(UserActive userActive) {
        if (userActive.getFlow() > 0) {
            BigDecimal totalYeild = new BigDecimal(String.valueOf(userActive.getTotalYeild()));
            BigDecimal flowYeild = new BigDecimal(String.valueOf(userActive.getFlow() * 0.0001));
            userActive.setTotalYeild(totalYeild.add(flowYeild).doubleValue());
            logger.info("【" + userActive.getUserName() + "】" + "使用了流量" + userActive.getFlow() + "M,年華收益率為"
                    + userActive.getTotalYeild());
        } else {
            logger.info("【" + userActive.getUserName() + "】" + "沒有使用流量,年華收益率為" + userActive.getTotalYeild());
        }
        if (successor != null) {
            successor.caculator(userActive);
        }
        return userActive.getTotalYeild();
    }

}

YeildCaculatorOfOneYuan

package com.charlie.wifi.yeild;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class YeildCaculatorOfOneYuan extends YeildCaculatorHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public YeildCaculatorOfOneYuan(String name) {
        super(name);
    }

    @Override
    public double caculator(UserActive userActive) {
        if (userActive.isOneYuan()) {
            BigDecimal totalYeild = new BigDecimal(String.valueOf(userActive.getTotalYeild()));
            BigDecimal oneYuanYeild = new BigDecimal("0.01");
            userActive.setTotalYeild(totalYeild.add(oneYuanYeild).doubleValue());
            logger.info("【" + userActive.getUserName() + "】" + "參與了1元加息,年華收益率為" + userActive.getTotalYeild());
        } else {
            logger.info("【" + userActive.getUserName() + "】" + "沒有參與了1元加息,年華收益率為" + userActive.getTotalYeild());
        }
        if (successor != null) {
            successor.caculator(userActive);
        }

        return userActive.getTotalYeild();
    }

}

YeildCaculatorOfShare

package com.charlie.wifi.yeild;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class YeildCaculatorOfShare extends YeildCaculatorHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public YeildCaculatorOfShare(String name) {
        super(name);
    }

    @Override
    public double caculator(UserActive userActive) {
        if (userActive.isShare()) {
            BigDecimal totalYeild = new BigDecimal(String.valueOf(userActive.getTotalYeild()));
            BigDecimal shareYeild = new BigDecimal("0.01");
            userActive.setTotalYeild(totalYeild.add(shareYeild).doubleValue());
            logger.info("【" + userActive.getUserName() + "】" + "分享了WIFI,年華收益率為" + userActive.getTotalYeild());
        } else {
            logger.info("【" + userActive.getUserName() + "】" + "沒有分享WIFI,年華收益率為" + userActive.getTotalYeild());
        }
        if (successor != null) {
            successor.caculator(userActive);
        }
        return userActive.getTotalYeild();
    }

}

YeildCaculatorOfVip

package com.charlie.wifi.yeild;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class YeildCaculatorOfVip extends YeildCaculatorHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public YeildCaculatorOfVip(String name) {
        super(name);
    }

    @Override
    public double caculator(UserActive userActive) {
        if (userActive.getVipCode() == 100) {
            BigDecimal totalYeild = new BigDecimal(String.valueOf(userActive.getTotalYeild()));
            BigDecimal vipYeild = new BigDecimal("0.02");
            userActive.setTotalYeild(totalYeild.add(vipYeild).doubleValue());
            logger.info("【" + userActive.getUserName() + "】" + "為VIP,年華收益率為" + userActive.getTotalYeild());
        } else {
            logger.info("【" + userActive.getUserName() + "】" + "為非VIP,年華收益率為" + userActive.getTotalYeild());
        }
        if (successor != null) {
            successor.caculator(userActive);
        }
        return userActive.getTotalYeild();
    }

}

YeildCaculatorOfWifiConnect

package com.charlie.wifi.yeild;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class YeildCaculatorOfWifiConnect extends YeildCaculatorHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public YeildCaculatorOfWifiConnect(String name) {
        super(name);
    }

    @Override
    public double caculator(UserActive userActive) {
        if (userActive.isWifiConnect()) {
            BigDecimal totalYeild = new BigDecimal(String.valueOf(userActive.getTotalYeild()));
            BigDecimal vipYeild = new BigDecimal("0.01");
            userActive.setTotalYeild(totalYeild.add(vipYeild).doubleValue());
            logger.info("【" + userActive.getUserName() + "】" + "連接了WIFI,年華收益率為" + userActive.getTotalYeild());
        } else {
            logger.info("【" + userActive.getUserName() + "】" + "沒有連接WIFI,年華收益率為" + userActive.getTotalYeild());
        }
        if (successor != null) {
            successor.caculator(userActive);
        }
        return userActive.getTotalYeild();
    }

}

Main

package com.charlie.wifi.yeild;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        UserActive xiaoming = new UserActive("小明", 0, false, false, 0, false);
        UserActive xiaowang = new UserActive("小王", 100, false, true, 0, false);
        UserActive xiaoli = new UserActive("小李", 0, true, false, 0, true);
        UserActive xiaojiang = new UserActive("小姜", 100, true, true, 100, true);

        YeildCaculatorHandler vip = new YeildCaculatorOfVip("VIP加息計(jì)算器");
        YeildCaculatorHandler oneYuan = new YeildCaculatorOfOneYuan("一元加息計(jì)算器");
        YeildCaculatorHandler wifiConnect = new YeildCaculatorOfWifiConnect("WIFI連接計(jì)算器");
        YeildCaculatorHandler share = new YeildCaculatorOfShare("分享WIFI計(jì)算器");
        YeildCaculatorHandler flow = new YeildCaculatorOfFlow("流量使用計(jì)算器");

        vip.setSuccessor(oneYuan);
        oneYuan.setSuccessor(wifiConnect);
        wifiConnect.setSuccessor(share);
        share.setSuccessor(flow);

        vip.caculator(xiaoming);
        logger.info("\n");
        vip.caculator(xiaowang);
        logger.info("\n");
        vip.caculator(xiaoli);
        logger.info("\n");
        vip.caculator(xiaojiang);

        logger.info("【小姜】最終年化收益率為" + xiaojiang.getTotalYeild());

    }

}

運(yùn)行結(jié)果

INFO  com.charlie.wifi.yeild.YeildCaculatorOfVip - 【小明】為非VIP,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfOneYuan - 【小明】沒有參與了1元加息,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfWifiConnect - 【小明】沒有連接WIFI,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小明】沒有分享WIFI,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小明】沒有使用流量,年華收益率為0.04
INFO  com.charlie.wifi.yeild.Main - 【小明】最終年化收益率為0.04

INFO  com.charlie.wifi.yeild.YeildCaculatorOfVip - 【小王】為VIP,年華收益率為0.06
INFO  com.charlie.wifi.yeild.YeildCaculatorOfOneYuan - 【小王】沒有參與了1元加息,年華收益率為0.06
INFO  com.charlie.wifi.yeild.YeildCaculatorOfWifiConnect - 【小王】連接了WIFI,年華收益率為0.07
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小王】沒有分享WIFI,年華收益率為0.07
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小王】沒有使用流量,年華收益率為0.07
INFO  com.charlie.wifi.yeild.Main - 【小王】最終年化收益率為0.07

INFO  com.charlie.wifi.yeild.YeildCaculatorOfVip - 【小李】為非VIP,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfOneYuan - 【小李】參與了1元加息,年華收益率為0.05
INFO  com.charlie.wifi.yeild.YeildCaculatorOfWifiConnect - 【小李】沒有連接WIFI,年華收益率為0.05
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小李】分享了WIFI,年華收益率為0.06
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小李】沒有使用流量,年華收益率為0.06
INFO  com.charlie.wifi.yeild.Main - 【小李】最終年化收益率為0.06

INFO  com.charlie.wifi.yeild.YeildCaculatorOfVip - 【小姜】為VIP,年華收益率為0.06
INFO  com.charlie.wifi.yeild.YeildCaculatorOfOneYuan - 【小姜】參與了1元加息,年華收益率為0.07
INFO  com.charlie.wifi.yeild.YeildCaculatorOfWifiConnect - 【小姜】連接了WIFI,年華收益率為0.08
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小姜】分享了WIFI,年華收益率為0.09
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小姜】使用了流量100M,年華收益率為0.1
INFO  com.charlie.wifi.yeild.Main - 【小姜】最終年化收益率為0.1

總結(jié)

通過重構(gòu),將用戶行為的查詢,不同行為的加息計(jì)算處理分別解耦,之前是全部耦合在一起。這樣維護(hù)起來非常方便,比如流量使用年化收益率的業(yè)務(wù)規(guī)則改變了,那么我就修改這個計(jì)算器就行,如果增加新的用戶加息行為,就再增加一個計(jì)算器,如果取消了某個用戶加息行為,就去掉就行,如果在之前幾百行的代碼里面去修改,就會顯得非常的頭疼。其實(shí)很多時候,當(dāng)業(yè)務(wù)規(guī)則簡單的時候,不使用設(shè)計(jì)模式,也沒有什么問題,維護(hù)起來也不難。只有當(dāng)業(yè)務(wù)規(guī)則非常之多,越來越復(fù)雜的時候,問題就會暴露出來。就像訪問量一樣,一個接口的訪問量是100w和100,接口的處理是完全不一樣的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容