重構(gòu)之入門到入土蔓纠,記一次重構(gòu)思路

項目背景

最近公司需要引入一款新的人臉設(shè)備腿倚,并且想要整合一下之前的設(shè)備敷燎,想要做到一個項目里面能使用兩個不同平臺的設(shè)備硬贯,這兩個平臺之前都做過對接饭豹,但是由于寫的人不同拄衰,所以邏輯上有一點點不一樣翘悉,但是其實也可以按照同樣的邏輯去寫妖混。

重構(gòu)第一步:抽取共性與差異

注意,重構(gòu)一定要在你熟悉業(yè)務(wù)與架構(gòu)的情況下進行重構(gòu)诗越,如果不熟悉嚷狞,并且沒有必要的情況下床未,不建議對代碼做任何修改振坚,經(jīng)過上線校驗的代碼渡八,寫的再差也比沒經(jīng)過驗證的代碼強。
以我這次重構(gòu)的一個步驟為例宏娄,人員信息同步(增加孵坚、修改),其實他就可以抽象成以下這么一個流程
獲取在線的設(shè)備 -> 檢查圖片質(zhì)量是否合格 -> 開啟線程異步同步 -> 檢查設(shè)備是否存在該人員 卖宠?修改 : 刪除

重構(gòu)第二步:根據(jù)第一步的流程確定架構(gòu)

這里先放一下原代碼扛伍,這段代碼在只有一種設(shè)備的情況下是沒有問題的蜒秤,但是現(xiàn)在我這里一個程序需要兼容不同的設(shè)備,并且設(shè)備的處理邏輯大體上是相同的帅刊,只不過與設(shè)備交互的地方有點不一樣

    private void doSyncPerson(PersonalInfo personalInfo, OperateType operateType, UserSyncReq userInfo, String address) {
        Integer deviceId;
        try {
            deviceId = deviceService.getDeviceId(address);
        } catch (Exception e) {
            throw new ServiceException("獲取設(shè)備id失敗,address: " + address);
        }
        if (isExistsPerson(address, deviceId, String.valueOf(userInfo.getUser_id()))) {
            operateType = OperateType.EditPerson;
            personalInfo.setOperator(operateType.name());
        }
        personalInfo.getInfo().setDeviceId(deviceId);
        HaiqingResp response = haiqingDeviceClient.post(address, operateType, personalInfo,HaiqingResp.class);
        if(response.isError()){
            throw new ServiceException("同步人員信息失敗");
        }
    }

    private PersonalInfo searchPerson(String address, int deviceId, String searchId) {
        Map<String, Object> json = new HashMap<>();
        json.put("operator", OperateType.SearchPerson.name());
        Map<String, Object> info = new HashMap();
        info.put("DeviceID", deviceId);
        info.put("SearchType", 0);
        info.put("SearchID", searchId);
        info.put("Picture", 0);
        json.put("info", info);
        return haiqingDeviceClient.post(address, OperateType.SearchPerson, json,PersonalInfo.class);

    }


    private boolean isExistsPerson(String address, int deviceId, String searchId) {
        PersonalInfo personalInfo = this.searchPerson(address, deviceId, searchId);
        if (personalInfo == null) {
            return false;
        }
        if (personalInfo.getInfo() == null) {
            return false;
        }
        return personalInfo.getInfo().getCustomizeId() != null;
    }

開始重構(gòu)

    @Override
    public AcmsRespDTO userSync(UserSyncReq userSyncReq) {
        List<String> device_address_list = userSyncReq.getDevice_address_list();
        userSyncReq.setDevice_address_list(filterOnlineDevices(device_address_list));
// checkImage是個接口方法 由子類實現(xiàn)
        boolean isPass = checkImage(userSyncReq.getPhoto(), userSyncReq.getDevice_address_list());
        if(!isPass){
            return AcmsRespDTO.error("圖片校驗失敗");
        }
        for (String address : userSyncReq.getDevice_address_list()) {
            ScheduleConfig scheduleConfig = new ScheduleConfig();
            scheduleConfig.setKey(IdUtil.fastSimpleUUID());
            scheduleConfig.setStartTime(new Date());
            scheduleConfig.setDelay(defaultDelay);
// 用戶同步的抽象類
            AbstractUserSyncThread userSyncThread = getUserSyncThread();
            userSyncThread.setScheduleConfig(scheduleConfig);
            userSyncThread.setUserSyncReq(userSyncReq);
            userSyncThread.setAddress(address);
            scheduleConfig.setRunnable(userSyncThread);
            scheduledTaskService.addPollingTask(scheduleConfig);
        }

        return  AcmsRespDTO.success();
    }

public abstract class AbstractUserSyncThread extends AbstractScheduleTimesRunnable {

    protected UserSyncReq userSyncReq;

    protected String address;

    @Override
    protected void timesRun() {
        if(checkUserExist()){
            log.info("用戶存在,修改");
            updateUser();
        }else{
            log.info("用戶不存在吧兔,新增");
            addUser();
        }
    }

    /**
     * 檢查用戶是否存在 子類實現(xiàn)
     * @return
     */
    protected abstract boolean checkUserExist();

//子類實現(xiàn)新增方法
    protected abstract void addUser();
//子類實現(xiàn)修改方法
    protected abstract void updateUser();

    public UserSyncReq getUserSyncReq() {
        return userSyncReq;
    }

    public void setUserSyncReq(UserSyncReq userSyncReq) {
        this.userSyncReq = userSyncReq;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

第三步:由子類確認(rèn)具體實現(xiàn)

這里以其中一個設(shè)備為例

@Service("HaiQing")
@Slf4j
public class HaiQingAcmsInterface extends AbstractAcmsInterface {

    @Autowired
    private HaiqingDeviceClient haiqingDeviceClient;

    @Override
    public AcmsRespDTO usePicCheck(String photo) {
        return null;
    }


    @Override
    public boolean checkImagePass(String photo, String address) {
        DetectFaceFromPicReq request = new DetectFaceFromPicReq();
        request.setOperator(OperateType.DetectFaceFromPic);
        DetectFaceFromPicReq.Info info = new DetectFaceFromPicReq.Info();
        info.setPicinfo(photo);
        request.setInfo(info);
        try {
            DetectFaceFromPicResp detectFaceFromPicResp = haiqingDeviceClient
                    .post(address, OperateType.DetectFaceFromPic, request, DetectFaceFromPicResp.class);
            int detectFace = Optional.ofNullable(detectFaceFromPicResp)
                    .map(DetectFaceFromPicResp::getInfo)
                    .map(DetectFaceFromPicResp.Info::getDetectFace)
                    .orElse(0);
            return detectFace == 1;
        } catch (Exception ignored) {
            log.error("校驗圖片異常",ignored);
        }
        return false;
    }

    @Override
    public AbstractUserSyncThread getUserSyncThread() {
        return new HaiQingUserSyncThread();
    }

    @Override
    public AbstractUserDelThread getUserDelThread() {
        return new HaiQingUserDelThread();
    }

    @Override
    public AbstractDeviceSyncThread getDeviceSyncThread() {
        return new HaiQingDeviceSyncThread();
    }
}
public class HaiQingUserSyncThread  extends AbstractUserSyncThread {

    private static HaiqingDeviceClient haiqingDeviceClient = SpringUtils.getBeanByClass(HaiqingDeviceClient.class);

    private static HaiQingDeviceService haiQingDeviceService = SpringUtils.getBeanByClass(HaiQingDeviceService.class);


    @Override
    protected boolean checkUserExist() {
        return haiQingDeviceService.checkUserExist(address,userSyncReq.getUser_id());
    }

    @Override
    protected void addUser() {
        PersonalInfo personalInfo = getPersonalInfo();
        personalInfo.setOperator(OperateType.AddPerson.name());
        HaiqingResp response = haiqingDeviceClient.post(address, OperateType.AddPerson, personalInfo,HaiqingResp.class);
        if(response.isOk()){
            stop();
        }
    }

    @Override
    protected void updateUser() {
        PersonalInfo personalInfo = getPersonalInfo();
        personalInfo.setOperator(OperateType.EditPerson.name());
        HaiqingResp response = haiqingDeviceClient.post(address, OperateType.EditPerson, personalInfo,HaiqingResp.class);
        if(response.isOk()){
            stop();
        }
    }

    private PersonalInfo getPersonalInfo(){
        PersonalInfo personalInfo = new PersonalInfo();
        personalInfo.setPicInfo(userSyncReq.getPhoto());
        Personal personal = new Personal();
        personal.setIdType(0);
        personal.setCustomizeId(Long.parseLong(userSyncReq.getUser_id()));
        personal.setTelnum(userSyncReq.getPhone());
        personal.setName(userSyncReq.getUser_name());
        personalInfo.setInfo(personal);

        Integer deviceId = haiQingDeviceService.getDeviceId(address);
        personal.setDeviceId(deviceId);

        return personalInfo;
    }
}

總結(jié)

公司內(nèi)部的代碼也就只能放部分片段了,重構(gòu)以后代碼相對來說更加清晰了一些吴藻,
說說重構(gòu)的好處和壞處弓柱,按照這種架構(gòu)的話呢矢空,它固定了程序的流程妇多,讓程序以一定的流程去執(zhí)行伤哺,但是也減少的一定的自由性,如果有其他設(shè)備要接入的話者祖,按照這套模式就非常簡單(按照這個架構(gòu)重構(gòu)另一個設(shè)備的代碼就只花了一個小時立莉,在對應(yīng)實現(xiàn)的地方把原來的代碼貼上去就行),但是如果你要改架構(gòu)七问,就會變得非常復(fù)雜蜓耻,還有,這種架構(gòu)也用到了模板設(shè)計模式械巡、工廠設(shè)計模式刹淌、對于新人來說可能會難以理解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末讥耗,一起剝皮案震驚了整個濱河市有勾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖荤懂,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粟耻,死亡現(xiàn)場離奇詭異,居然都是意外死亡册烈,警方通過查閱死者的電腦和手機扭倾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門模聋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人工窍,你說我怎么就攤上這事薪者。” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么聪铺? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任番宁,我火速辦了婚禮火欧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘于未。我一直安慰自己闷叉,他們只是感情好品擎,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布西设。 她就那樣靜靜地躺著梦碗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天香府,我揣著相機與錄音柠硕,去河邊找鬼闻葵。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的霞扬。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝙昙,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤吓妆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鸭栖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晕鹊,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡溅话,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年躁锁,在試婚紗的時候發(fā)現(xiàn)自己被綠了以躯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斩箫。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡纳决,死狀恐怖碰逸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阔加,我是刑警寧澤饵史,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站胜榔,受9級特大地震影響胳喷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夭织,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一吭露、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尊惰,春花似錦讲竿、人聲如沸纬向。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逾条。三九已至,卻和暖如春投剥,著一層夾襖步出監(jiān)牢的瞬間师脂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工江锨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吃警,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓啄育,卻偏偏與公主長得像酌心,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子挑豌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

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