重构之入门到入土,记一次重构思路

项目背景

最近公司需要引入一款新的人脸设备,并且想要整合一下之前的设备,想要做到一个项目里面能使用两个不同平台的设备,这两个平台之前都做过对接,但是由于写的人不同,所以逻辑上有一点点不一样,但是其实也可以按照同样的逻辑去写。

重构第一步:抽取共性与差异

注意,重构一定要在你熟悉业务与架构的情况下进行重构,如果不熟悉,并且没有必要的情况下,不建议对代码做任何修改,经过上线校验的代码,写的再差也比没经过验证的代码强。
以我这次重构的一个步骤为例,人员信息同步(增加、修改),其实他就可以抽象成以下这么一个流程
获取在线的设备 -> 检查图片质量是否合格 -> 开启线程异步同步 -> 检查设备是否存在该人员 ?修改 : 删除

重构第二步:根据第一步的流程确定架构

这里先放一下原代码,这段代码在只有一种设备的情况下是没有问题的,但是现在我这里一个程序需要兼容不同的设备,并且设备的处理逻辑大体上是相同的,只不过与设备交互的地方有点不一样

    private void doSyncPerson(PersonalInfo personalInfo, OperateType operateType, UserSyncReq userInfo, String address) {
        Integer deviceId;
        try {
            deviceId = deviceService.getDeviceId(address);
        } catch (Exception e) {
            throw new ServiceException("获取设备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;
    }

开始重构

    @Override
    public AcmsRespDTO userSync(UserSyncReq userSyncReq) {
        List<String> device_address_list = userSyncReq.getDevice_address_list();
        userSyncReq.setDevice_address_list(filterOnlineDevices(device_address_list));
// checkImage是个接口方法 由子类实现
        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();
        }
    }

    /**
     * 检查用户是否存在 子类实现
     * @return
     */
    protected abstract boolean checkUserExist();

//子类实现新增方法
    protected abstract void addUser();
//子类实现修改方法
    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;
    }
}

第三步:由子类确认具体实现

这里以其中一个设备为例

@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;
    }
}

总结

公司内部的代码也就只能放部分片段了,重构以后代码相对来说更加清晰了一些,
说说重构的好处和坏处,按照这种架构的话呢,它固定了程序的流程,让程序以一定的流程去执行,但是也减少的一定的自由性,如果有其他设备要接入的话,按照这套模式就非常简单(按照这个架构重构另一个设备的代码就只花了一个小时,在对应实现的地方把原来的代码贴上去就行),但是如果你要改架构,就会变得非常复杂,还有,这种架构也用到了模板设计模式、工厂设计模式、对于新人来说可能会难以理解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容