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

在業(yè)務(wù)開(kāi)發(fā)中孙援,為了處理某個(gè)屬性害淤,可能需要復(fù)雜的處理邏輯,才能得到拓售,一般的做法是按步驟處理窥摄,最終得到想要的結(jié)果。作者的業(yè)務(wù)場(chǎng)景為計(jì)算用戶的年化收益率础淤,這個(gè)年化收益率是根據(jù)用戶的行為計(jì)算而來(lái)崭放。目前項(xiàng)目中的代碼是按常規(guī)步驟處理,代碼非掣胄祝混亂币砂,今天重新看一下代碼,覺(jué)得可以使用職責(zé)鏈模式來(lái)解決吱瘩。

業(yè)務(wù)場(chǎng)景:

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

用戶行為:

這里只列出以下幾種票摇,實(shí)際情況更加復(fù)雜拘鞋,種類(lèi)跟多

1.是否為vip
2.是否分享過(guò)wifi
3.是否使用過(guò)連接wifi
4.通過(guò)連接wifi使用的流量,流量使用越多矢门,加息越多
5.是否支付1元盆色,購(gòu)買(mǎi)加息

當(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;//如果連接過(guò)wifi祟剔,就增加0.01
}
//如果分享過(guò)wifi隔躲,就增加0.01
//如果...,就增加...
...
return totalYield;

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

類(lèi)圖

年化收益率類(lèi)圖.JPG
  • UserActive 用戶行為
  • YeildCaculatorHandler 抽象類(lèi)年化收益率計(jì)算器
  • YeildCaculatorOfVip vip年化收益率計(jì)算器
  • YeildCaculatorOfFlow 流量使用年化收益率計(jì)算器
  • YeildCaculatorOfOneYuan 購(gòu)買(mǎi)一元加息年化收益率計(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() + "】" + "沒(méi)有使用流量组力,年華收益率為" + 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() + "】" + "沒(méi)有參與了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() + "】" + "沒(méi)有分享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() + "】" + "沒(méi)有連接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 - 【小明】沒(méi)有參與了1元加息,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfWifiConnect - 【小明】沒(méi)有連接WIFI拉馋,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小明】沒(méi)有分享WIFI榨为,年華收益率為0.04
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小明】沒(méi)有使用流量,年華收益率為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 - 【小王】沒(méi)有參與了1元加息随闺,年華收益率為0.06
INFO  com.charlie.wifi.yeild.YeildCaculatorOfWifiConnect - 【小王】連接了WIFI,年華收益率為0.07
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小王】沒(méi)有分享WIFI蔓腐,年華收益率為0.07
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小王】沒(méi)有使用流量矩乐,年華收益率為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 - 【小李】沒(méi)有連接WIFI散罕,年華收益率為0.05
INFO  com.charlie.wifi.yeild.YeildCaculatorOfShare - 【小李】分享了WIFI,年華收益率為0.06
INFO  com.charlie.wifi.yeild.YeildCaculatorOfFlow - 【小李】沒(méi)有使用流量傀蓉,年華收益率為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é)

通過(guò)重構(gòu)谱净,將用戶行為的查詢(xún)窑邦,不同行為的加息計(jì)算處理分別解耦,之前是全部耦合在一起壕探。這樣維護(hù)起來(lái)非常方便冈钦,比如流量使用年化收益率的業(yè)務(wù)規(guī)則改變了,那么我就修改這個(gè)計(jì)算器就行浩蓉,如果增加新的用戶加息行為派继,就再增加一個(gè)計(jì)算器宾袜,如果取消了某個(gè)用戶加息行為,就去掉就行驾窟,如果在之前幾百行的代碼里面去修改庆猫,就會(huì)顯得非常的頭疼。其實(shí)很多時(shí)候绅络,當(dāng)業(yè)務(wù)規(guī)則簡(jiǎn)單的時(shí)候月培,不使用設(shè)計(jì)模式,也沒(méi)有什么問(wèn)題恩急,維護(hù)起來(lái)也不難杉畜。只有當(dāng)業(yè)務(wù)規(guī)則非常之多,越來(lái)越復(fù)雜的時(shí)候衷恭,問(wèn)題就會(huì)暴露出來(lái)此叠。就像訪問(wèn)量一樣,一個(gè)接口的訪問(wèn)量是100w和100随珠,接口的處理是完全不一樣的灭袁。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市窗看,隨后出現(xiàn)的幾起案子茸歧,更是在濱河造成了極大的恐慌,老刑警劉巖显沈,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件软瞎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拉讯,警方通過(guò)查閱死者的電腦和手機(jī)涤浇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)遂唧,“玉大人芙代,你說(shuō)我怎么就攤上這事「桥恚” “怎么了纹烹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)召边。 經(jīng)常有香客問(wèn)我铺呵,道長(zhǎng),這世上最難降的妖魔是什么隧熙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任片挂,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘音念。我一直安慰自己沪饺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布闷愤。 她就那樣靜靜地躺著整葡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讥脐。 梳的紋絲不亂的頭發(fā)上遭居,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音旬渠,去河邊找鬼俱萍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛告丢,可吹牛的內(nèi)容都是我干的枪蘑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼芋齿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼腥寇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起觅捆,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎麻敌,沒(méi)想到半個(gè)月后栅炒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡术羔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年赢赊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片级历。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡释移,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寥殖,到底是詐尸還是另有隱情玩讳,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布嚼贡,位于F島的核電站熏纯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏粤策。R本人自食惡果不足惜樟澜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秩贰,春花似錦霹俺、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝗罗,卻和暖如春艇棕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背串塑。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工沼琉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桩匪。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓打瘪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親傻昙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闺骚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容