浅谈代码重构与优化

浅谈代码重构与优化

前几天看到有一篇不错的文章减少该死的if-else嵌套,觉得写得很不错,整理了一下后准备在团队内部简单分享一下。

写在前面

大家在接手项目的时候,应该有遇到过下面这种结构的代码

if (true) {
    .....
    if (true) {
        if (true) {
            ....
            if (true) {
                if (true) {
                    ......
                }
            }
            // do something
        }
       // do something
       if (true) {
           .........
       }
    }
    // do something
}

看到这些代码,第一反应是脑壳痛,N多的if-else已经将这段代码的逻辑变得十分复杂,代码的可读性和可维护性也会变得极差。下面举个实际案例来介绍如何优化这种代码。

实际案例

业务需求:提供一个服务,可以让用户分享链接、图片、文本和图文,并将分享结果回调给用户。

初看这个业务很需求很简单,先写一个简单的demo

public class ShareItem {

    public static final int TYPE_LINK = 0;
    public static final int TYPE_IMAGE = 1;
    public static final int TYPE_TEXT = 2;
    public static final int TYPE_IMAGE_TEXT = 3;

    public int type;
    public String title;
    public String content;
    public String imagePath;
    public String link;
}
public void share (ShareItem item, ShareListener listener) {
    if (item != null) {
        if (item.type == TYPE_LINK) {
            // 分享链接
            if (!StringUtils.isEmpty(item.link) && !StringUtils.isEmpty(item.title)) {
                doShareLink(item.link, item.title, item.content, listener);
            } else {
                if (listener != null) {
                    listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
                }
            }
        } else if (item.type == TYPE_IMAGE) {
            // 分享图片
            if (!StringUtils.isEmpty(item.imagePath)) {
                doShareImage(item.imagePath, listener);
            } else {
                if (listener != null) {
                    listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
                }
            }
        } else if (item.type == TYPE_TEXT) {
            // 分享文本
            if (!StringUtils.isEmpty(item.content)) {
                doShareText(item.content, listener);
            } else {
                if (listener != null) {
                    listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
                }
            }
        } else if (item.type == TYPE_IMAGE_TEXT) {
            // 分享图文
            if (!StringUtils.isEmpty(item.imagePath) && !StringUtils.isEmpty(item.content)) {
                doShareImageAndText(item.imagePath, item.content, listener);
            } else {
                if (listener != null) {
                    listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
                }
            }
        } else {
            if (listener != null) {
                listener.onCallback(ShareListener.STATE_FAIL, "不支持的分享类型");
            }
        }
    } else {
        if (listener != null) {
            listener.onCallback(ShareListener.STATE_FAIL, "ShareItem 不能为 null");
        }
    }
}

上面这段代码,写完后好像没啥问题,至少思路是清晰的,但是如果经过几轮需求的摧残,这个代码可能就会变得很爆炸。比如说,新增了好几个分享方式,那if-else就会一直往下叠,更不用说如果产品来了一些定制化的需求,if-else里面就会再嵌if-else,最终极可能会得和最上面的代码例子一样了。

分层、卫语句

分层

接口分为外部和内部接口,所有空值判断放在外部接口完成,只处理一次;而内部接口传入的变量由外部接口保证不为空,从而减少空值判断。

Controller(简单校验) -> Service(核心业务处理) -> Data

Controller -> InternalService(简单校验) -> Service(核心业务处理) -> Data

卫语句

将异常流提前返回,好处是可以将异常流和正常流的代码分开,让开发人员将精力更聚焦在正常的业务流程上面,而且这种方式也能有效地较少if—else的嵌套层数。

if (a != null) {
    // 正常流
} else {
    // 异常流
}
if (a == null) {
    // 异常流
    return;
}

// 正常流

改造后的代码

public boolean share(ShareItem item, ShareListener listener) {
    // 前置校验
    if (listener == null) {
        log.error("listener 不能为空!");
        return false;
    }
    if (item == null) {
        log.error("shareItem 不能为空!");
        return false;
    }

    // 核心业务处理
    shareProcess(item, listener);
    return true;
}

public void shareProcess(ShareItem item, ShareListener listener) {
    if (item.type == TYPE_LINK) {
        // 分享链接
        if (!StringUtils.isEmpty(item.link) && !StringUtils.isEmpty(item.title)) {
            doShareLink(item.link, item.title, item.content, listener);
        } else {
            listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
        }
    } else if (item.type == TYPE_IMAGE) {
        // 分享图片
        if (!StringUtils.isEmpty(item.imagePath)) {
            doShareImage(item.imagePath, listener);
        } else {
            listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
        }
    } else if (item.type == TYPE_TEXT) {
        // 分享文本
        if (!StringUtils.isEmpty(item.content)) {
            doShareText(item.content, listener);
        } else {
            listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
        }
    } else if (item.type == TYPE_IMAGE_TEXT) {
        // 分享图文
        if (!StringUtils.isEmpty(item.imagePath) && !StringUtils.isEmpty(item.content)) {
            doShareImageAndText(item.imagePath, item.content, listener);
        } else {
            listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
        }
    } else {
        listener.onCallback(ShareListener.STATE_FAIL, "不支持的分享类型");
    }
}

多态

利用多态,每种业务单独处理,在接口不再做任何业务判断。把ShareItem抽象出来,作为基础类,然后针对每种业务各自实现其子类:

public abstract class ShareItem {

    public static final int TYPE_LINK = 0;
    public static final int TYPE_IMAGE = 1;
    public static final int TYPE_TEXT = 2;
    public static final int TYPE_IMAGE_TEXT = 3;

    public int type;

    public ShareItem(int type) {
        this.type = type;
    }

    public abstract boolean validate();

    public abstract void doShare(ShareListener listener);
}
public class LinkShareItem extends ShareItem {

    private String title;
    private String content;
    private String link;

    public LinkShareItem(String title, String content, String link) {
        super(TYPE_LINK);
        this.title = title;
        this.content = content;
        this.link = link;
    }

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {
        // do share
    }
}

public class ImageShareItem extends ShareItem {

    private String imagePath;

    public ImageShareItem(String imagePath) {
        super(ShareItem.TYPE_IMAGE);
        this.imagePath = imagePath;
    }

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {
        // do share
    }
}

public class ImageTextShareItem extends ShareItem {

    private String content;
    private String imagePath;

    public ImageTextShareItem(String content, String imagePath) {
        super(ShareItem.TYPE_IMAGE_TEXT);
        this.content = content;
        this.imagePath = imagePath;
    }

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {
        // do share
    }
}

public class TextShareItem extends ShareItem {

    private String content;

    public TextShareItem(String content) {
        super(ShareItem.TYPE_TEXT);
        this.content = content;
    }

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {
        // do share
    }
}

将实现分离出来后,方法就变得很简洁了,if-else基本都已经被消除,以后如果新增一种分享方式,就只需要编写对应的实现方式就可以了。

public void share(ShareItem item, ShareListener listener) {
    // 前置校验
    if (listener == null) {
        log.error("listener 不能为空!");
        return;
    }
    if (item == null) {
        log.error("shareItem 不能为空!");
        return;
    }

    // 核心业务处理
    shareProcess(item, listener);
}

public void shareProcess(ShareItem item, ShareListener listener) {
    boolean validateRet = item.validate();
    if (!validateRet) {
        listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
        return;
    }

    item.doShare(listener);
}

策略模式

上面的多态模式,是不是看上去已经很完美了?不过在我眼里其实不然,有一点不太合理的是,ShareItem作为POJO,里面不适应做过多的业务实现。目前贫血模式下,ShareItem应该作为一个BO,里面只放基础的属性值,而业务实现应该都放到各自的service里面。

这时候我们可以考虑使用策略模式对其进行优化。

将原ShareItem的业务逻辑代码移除,仅保留基础的属性

public abstract class ShareItem {
    public static final int TYPE_LINK = 0;
    public static final int TYPE_IMAGE = 1;
    public static final int TYPE_TEXT = 2;
    public static final int TYPE_IMAGE_TEXT = 3;

    public int type;
}

public class ImageShareItem extends ShareItem {
    private String imagePath;
}

public class ImageTextShareItem extends ShareItem {
    private String content;
    private String imagePath;
}

public class LinkShareItem extends ShareItem {
    private String title;
    private String content;
    private String link;
}

public class TextShareItem extends ShareItem {
    private String content;
}

编写策略类

public abstract class AbstractShareHandler {

    public abstract boolean validate();

    public abstract void doShare(ShareListener listener);

    public abstract int getShareType();
}

@Service
public class ImageShareHandle extends AbstractShareHandler {

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {

    }

    @Override
    public int getShareType() {
        return ShareItem.TYPE_IMAGE;
    }
}

@Service
public class ImageTextShareHandler extends AbstractShareHandler {

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {

    }

    @Override
    public int getShareType() {
        return ShareItem.TYPE_IMAGE_TEXT;
    }
}

@Service
public class LinkShareHandler extends AbstractShareHandler {

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {

    }

    @Override
    public int getShareType() {
        return ShareItem.TYPE_LINK;
    }
}

@Service
public class TextShareHandler extends AbstractShareHandler {

    @Override
    public boolean validate() {
        return false;
    }

    @Override
    public void doShare(ShareListener listener) {

    }

    @Override
    public int getShareType() {
        return ShareItem.TYPE_TEXT;
    }
}

创建一个Manager类用来获取和管理策略

@Service
public class ShareManager implements InitializingBean, ApplicationContextAware {

    /**
     * 策略集合
     */
    private Map<Integer, AbstractShareHandler> shareHandlerMap = new HashMap<>();

    private ApplicationContext applicationContext;

    /**
     * 获取处理的策略
     * @param shareType
     * @return
     */
    public AbstractShareHandler getHandler(Integer shareType) {
        AbstractShareHandler shareHandler = shareHandlerMap.get(shareType);
        if (shareHandler == null) {
            throw new IllegalArgumentException("shareType handler not found, shareType=" + shareType);
        }
        return shareHandler;
    }

    @Override
    public void afterPropertiesSet() {
        // 自动注入策略
        Map<String, AbstractShareHandler> shareImplMap = applicationContext.getBeansOfType(AbstractShareHandler.class);
        for (AbstractShareHandler handler : shareImplMap.values()) {
            shareHandlerMap.put(handler.getShareType(), handler);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

最后调整后的share方法就会变为下图那样

@Resource
private ShareManager shareManager;

public void share(ShareItem item, ShareListener listener) {
    // 前置校验
    if (listener == null) {
        log.error("listener 不能为空!");
        return;
    }
    if (item == null) {
        log.error("shareItem 不能为空!");
        return;
    }

    // 核心业务处理
    shareProcess(item, listener);
}

private void shareProcess(ShareItem item, ShareListener listener) {
    AbstractShareHandler handler = shareManager.getHandler(item.getType());

    if (!handler.validate()) {
        listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
        return;
    }

    handler.doShare(listener);
}

至此,我们就用策略模式对这段代码进行了优化,看上去是不是比之前的版本好多了呢?

原文地址:https://www.cnblogs.com/miguel/p/10612477.html

时间: 2024-10-02 02:23:51

浅谈代码重构与优化的相关文章

转:浅谈CSS在前端优化中一些值得注意的关键点

前端优化工作中要考虑的元素多种多样,而合理地使用CSS脚本可以在很大程度上优化页面的加载性能,以下我们就来浅谈CSS在前端优化中一些值得注意的关键点: 当谈到Web的“高性能”时,很多人想到的是页面加载时间,但其实性能不仅仅是指加载时间,还包括浏览器性能.网络性能.开发效率.在Web前端开发中,性能是一个非常重要的需要考虑的点.本文将介绍一些开发原则和性能准则,这些都是提高Web前端性能的基础. 1. 开发原则 1.1 编写符合当代浏览器性能的代码如果想提高前端性能,就必须理解浏览器的工作原理,

【浅谈DOM事件的优化】

浅谈DOM事件的优化 在 JavaScript程序的开发中,经常会用到一些频繁触发的 DOM 事件,如 mousemove.resize,还有不是那么常用的鼠标滚轮事件:mousewheel (在 Firefox 中,滚轮事件为 DOMMouseScroll). 浏览器为了确保这些事件能够及时响应,触发的频率会比较高,具体的触发频率各浏览器虽然有出入,但出入不大.很多时候在需要注重性能的场景下使用这些事件会想各种办法对事件的触发频率进行优化,下面说说我的一些优化方法. mousemove 在拖拽

浅谈tomcat中间件的优化【转】

今天来总结一下tomcat的一些优化的方案,由于本人才疏学浅,写的不好,勿喷! tomcat对于大多数从事开发工作的童鞋应该不会很陌生,通常做为默认的开发环境来为大家服务,不过tomcat默认的一些配置对于生产环境来说是相当不够滴,特别对于内存以及线程的配置方面都很有可能成为日后性能的瓶颈. 接下来咱们就聊聊tomcat的优化,从内存以及线程两个方面来谈: 1.内存方面 tomcat的内存优化操作起来就比较简单了 如果是linux环境的话设置如下: 修改TOMCAT_HOME/bin/catal

CSS代码重构与优化之路

写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多,如果没有及时对CSS代码进行维护,CSS代码不断会越来越多.CSS代码交错复杂,像一张庞大的蜘蛛网分布在网站的各个位置,你不知道修改这行代码会有什么影响,所以如果有修改或增加新功能时,开发人员往往不敢去删除旧的冗余的代码,而保险地增加新代码,最终的坏处就是项目中的CSS会越来越多,最终陷入无底洞. CSS代码重构的目的 我们写CSS代码时,不仅仅只是完成页面设计的效果,还应该让CSS代码易于管理,维护.我们对CSS

运维角度浅谈:MySQL数据库优化

日志君导读: 一个成熟的数据库架构并不是一开始设计就具备高可用.高伸缩等特性的,它是随着用户量的增加,基础架构才逐渐完善. 作者:zhenliang8,本文转自51CTO博客,点击原文阅读查看网页版文章. 本博文主要谈MySQL数据库发展周期中所面临的问题及优化方案,暂且抛开前端应用不说,大致分为以下五个阶段: 1.数据库表设计 项目立项后,开发部根据产品部需求开发项目,开发工程师工作其中一部分就是对表结构设计.对于数据库来说,这点很重要,如果设计不当,会直接影响访问速度和用户体验.影响的因素很

辛星浅谈大型网站构架优化思路之一简化

其实谈到大型网站,它和小型的站点几乎是两个概念,其概念的差别就像航空母舰和独木舟的区别那样,中国早在黄帝炎帝时代就可以制作独木舟了,但是生产航空母舰呢?因为航空母舰太大了,规模的提升带来了很多问题,那么如何去分析并且解决这些问题呢? 我感觉大型网站更应该去简化,不应该为了复杂而复杂,我感觉一套优秀的简化方案是优化网站的最有效的途径,没有之一,什么意思呢?如果让我们的货车跑得更快,那么少拉一些不必要的货物是最有效的方式,也应该是我们真正去优化一个网站的第一步. 那么该如何去简化呢?我们不妨从可以简

浅谈ORACLE SQL语句优化经验

(1) 选择最有效率的表名顺序(只在基于规则的seo/' target='_blank'>优化器中有效): ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. (2) WHERE子句中的连接顺序.

浅谈Vue 项目性能优化 经验

我优化公司的项目总结的几点: 1.先查看引入的图片大小,如果太大了,可以压缩,压缩路径:https://zhitu.isux.us/ 2.代码包优化, 待下项目开发完成.进行打包源码上线环节,需要对项目开发环节的开发提示信息以及错误信息进行屏蔽,一方面可以减少上线代码包的大小:另一方面提高系统的安全性.在vuejs项目的config目录下有三个文件dev.env.js(开发环境配置文件).prod.env.js(上线配置文件).index.js(通用配置文件).vue-cli脚手架在上线配置文件

浅谈代码混淆加固技术

随着移动互联网的快速发展,应用的安全问题不断涌现出来,于是越来越多的应用开发者将核心代码由java层转到native层,以对抗成熟的java逆向分析工具,然而如果native层的代码如果没有进行任何保护,还是比较容易被逆向分析工作者获取其运行逻辑,进而完成应用破解或者进行其他的操作.那么提高native代码的安全性有什么好办法吗?答案是肯定的,今天我们就来介绍一种有效对抗native层代码分析的方法--代码混淆技术. 那么,什么是代码混淆呢?代码混淆的学术定义如下: 代码混淆(code obfu