前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >防御性编程失败,我开始优化我写的多重 if-else 代码

防御性编程失败,我开始优化我写的多重 if-else 代码

原创
作者头像
Lorin 洛林
修改于 2024-01-16 11:34:56
修改于 2024-01-16 11:34:56
2520
举报

前言

  • 最近防御性编程比较火,不信邪的我在开发中进行了尝试,然后我写下了如下的代码:
代码语言:java
AI代码解释
复制
    public static void main(String[] args) {
        // do something
        if ("满足条件A") {
            // 查询权限
            if ("是否具备权限A" && "是否具备权限B") {
                // 查询配置
                if ("配置是否开启"){
                    // do something
                }
            }
        }
        // do something
    }
  • 不出意外我被逮捕了,组内另外一位同事对我的代码进行了 CodeReview,我的防御性编程编程没有幸运逃脱,被标记上了“多重 if-else ”需要进行优化,至此我的第一次防御性编程失败,开始了优化多重 if-else 之路,下面是我总结出的常用几种优化方式。

版本

  • Java8

几种常用的优化方式

提前使用 return 返回去除不必要的 else

  • 如果我们的代码块中需要使用 return 返回,我们应该尽可能早的使用 return 返回而不是使用 else
  • 优化前
代码语言:java
AI代码解释
复制
    private static boolean extracted(boolean condition) {
        if (condition) {
            // do something
            return false;
        }else {
            // do something
            return true;
        }
    }
  • 优化后
代码语言:java
AI代码解释
复制
    private static boolean extracted(boolean condition) {
        if (condition) {
            // do something
            return false;
        }
        
        // do something
        return true;
    }

使用三目运算符

  • 一些简单的逻辑我们可以使用三目运算符替代 if-else ,这样可以让我们的代码更加简洁
  • 优化前
代码语言:java
AI代码解释
复制
        int num = 0;
        if (condition) {
            num = 1;
        } else {
            num = 2;
        }
  • 优化后
代码语言:java
AI代码解释
复制
int num = condition ? 1 : 2;

使用枚举

  • 在某一些场景我们也可以使用枚举来优化多重 if-else 代码,使我们的代码更加简洁、具备更多的可读性和可维护性。
  • 优化前
代码语言:java
AI代码解释
复制
        String OrderStatusDes;
        if (orderStatus == 0) {
            OrderStatusDes = "订单未支付";
        } else if (orderStatus == 1) {
            OrderStatusDes = "订单已支付";
        } else if (orderStatus == 2) {
            OrderStatusDes = "已发货";
        } else {
            throw new Exception("Invalid order status");
        }
  • 优化后
代码语言:java
AI代码解释
复制
public enum OrderStatusEnum {
    UN_PAID(0, "订单未支付"),
    PAIDED(1, "订单已支付"),
    SENDED(2, "已发货"),
    ;

    private final int code;
    private final String desc;

    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    OrderStatusEnum(int index, String desc) {
        this.code = index;
        this.desc = desc;
    }

    public static OrderStatusEnum getOrderStatusEnum(int orderStatusCode) {
        for (OrderStatusEnum statusEnum : OrderStatusEnum.values()) {
            if (statusEnum.getCode() == orderStatusCode) {
                return statusEnum;
            }
        }
        return null;
    }
}


// 当然你需要根据业务场景对异常值做出合适的处理
OrderStatusEnum.getOrderStatusEnum(2)

抽取条件判断作为单独的方法

  • 当我们某个逻辑条件判断比较复杂时,可以考虑将判断条件抽离为单独的方法,这样可以使我们主流程逻辑更加清晰
  • 优化前
代码语言:java
AI代码解释
复制
        // do something
        if ("满足条件A" && "满足条件B") {
            // 查询权限
            if ("是否具备权限A" && "是否具备权限B") {
                // do something
            }
        }
        // do something
  • 优化后
代码语言:java
AI代码解释
复制
    public static void main(String[] args) {
        // do something
        if (hasSomePermission()) {
            // do something
        }
        // do something
    }

    private static boolean hasSomePermission() {
        if (!"满足条件A" || !"满足条件B") {
            return false;
        }
        // 查询权限
        return "是否具备权限A" && "是否具备权限B";
    }

有时候 switch 比 if-else 更加合适

  • 当条件为清晰的变量和枚举、或者单值匹配时,switch 比 if-else 更加合适,可以我们带好更好的可读性以及更好的性能 O(1)
  • 优化前
代码语言:java
AI代码解释
复制
if (day == Day.MONDAY) {
    // 处理星期一的逻辑
} else if (day == Day.TUESDAY) {
    // 处理星期二的逻辑
} else if (day == Day.WEDNESDAY) {
    // 处理星期三的逻辑
} else if (day == Day.THURSDAY) {
    // 处理星期四的逻辑
} else if (day == Day.FRIDAY) {
    // 处理星期五的逻辑
} else if (day == Day.SATURDAY) {
    // 处理星期六的逻辑
} else if (day == Day.SUNDAY) {
    // 处理星期日的逻辑
} else {
    // 处理其他情况
}
  • 优化后
代码语言:java
AI代码解释
复制
// 使用 switch 处理枚举类型
switch (day) {
    case MONDAY:
        // 处理星期一的逻辑
        break;
    case TUESDAY:
        // 处理星期二的逻辑
        break;
    // ...
    default:
        // 处理其他情况
        break;
}

策略模式 + 简单工厂模式

  • 前面我们介绍一些常规、比较简单的优化方法,但是在一些更加复杂的场景(比如多渠道对接、多方案实现等)我们可以结合一些场景的设计模式来实现让我们的代码更加优雅和可维护性,比如策略模式 + 简单工厂模式。
  • 优化前
代码语言:java
AI代码解释
复制
    public static void main(String[] args) {
        // 比如我们商场有多个通知渠道
        // 我们需要根据不同的条件使用不同的通知渠道
        if ("满足条件A") {
            // 构建渠道A
            // 通知
        } else if ("满足条件B") {
            // 构建渠道B
            // 通知
        } else {
            // 构建渠道C
            // 通知
        }
    }
// 上面的代码不仅维护起来麻烦同时可读性也比较差,我们可以使用策略模式 + 简单工厂模式
  • 优化后
代码语言:java
AI代码解释
复制
import java.util.HashMap;
import java.util.Map;

// 定义通知渠道接口
interface NotificationChannel {
    void notifyUser(String message);
}

// 实现具体的通知渠道A
class ChannelA implements NotificationChannel {
    @Override
    public void notifyUser(String message) {
        System.out.println("通过渠道A发送通知:" + message);
    }
}

// 实现具体的通知渠道B
class ChannelB implements NotificationChannel {
    @Override
    public void notifyUser(String message) {
        System.out.println("通过渠道B发送通知:" + message);
    }
}

// 实现具体的通知渠道C
class ChannelC implements NotificationChannel {
    @Override
    public void notifyUser(String message) {
        System.out.println("通过渠道C发送通知:" + message);
    }
}

// 通知渠道工厂
class NotificationChannelFactory {
    private static final Map<String, Class<? extends NotificationChannel>> channelMap = new HashMap<>();

    static {
        channelMap.put("A", ChannelA.class);
        channelMap.put("B", ChannelB.class);
        channelMap.put("C", ChannelC.class);
    }

    public static NotificationChannel createChannel(String channelType) {
        try {
            Class<? extends NotificationChannel> channelClass = channelMap.get(channelType);
            if (channelClass == null) {
                throw new IllegalArgumentException("不支持的通知渠道类型");
            }
            return channelClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("无法创建通知渠道", e);
        }
    }
}

// 客户端代码
public class NotificationClient {
    public static void main(String[] args) {
        // 根据条件选择通知渠道类型
        String channelType = "A";
        // 使用简单工厂创建通知渠道
        NotificationChannel channel = NotificationChannelFactory.createChannel(channelType);

        // 执行通知
        channel.notifyUser("这是一条通知消息");
    }
}
  • 有时候我们还可以借助 Spring IOC 能力的自动实现策略类的导入,然后使用 getBean() 方法获取对应的策略类实例,可以根据我们的实际情况灵活选择。

如何优化开头的代码

  • 好了现在回到开头,如果是你会进行怎么优化,下面是我交出的答卷,大家也可以在评论区发表自己的看法,欢迎一起交流:
代码语言:java
AI代码解释
复制
   public static void main(String[] args) {
        // do something
        if (isMeetCondition()) {
            // 查询配置
            // 此处查询配置的值需要在具体的任务中使用,所有并没抽离
            if ("配置是否开启") {
                // do something
            }
        }
        // do something
    }

    /**
     * 判断是否满足执行条件
     */
    private static boolean isMeetCondition() {
        if (!"满足条件A") {
            return false;
        }
        // 查询权限
        return "是否具备权限A" && "是否具备权限B";
    }

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
图像二值化方法汇总介绍
ImageJ中图像二值化方法介绍 概述 二值图像分析在对象识别与模式匹配中有重要作用,同时也在机器人视觉中也是图像处理的关键步骤,选择不同图像二值化方法得到的结果也不尽相同。本文介绍超过十种以上的基于
OpenCV学堂
2018/04/04
4.7K1
图像二值化方法汇总介绍
Task05 图像分割/二值化
该部分的学习内容是对经典的阈值分割算法进行回顾,图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。它不仅可以极大的压缩数据量,而且也大大简化了分析和处理步骤,因此在很多情况下,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。图像阈值化的目的是要按照灰度级,对像素集合进行一个划分,得到的每个子集形成一个与现实景物相对应的区域,各个区域内部具有一致的属性,而相邻区域不具有这种一致属性。这样的划分可以通过从灰度级出发选取一个或多个阈值来实现。
致Great
2020/05/06
1.3K0
OpenCV基础 | 11.图像二值化
学习视频可参见python+opencv3.3视频教学 基础入门[1] outline 图像二值化 二值图像 图像二值化方法 OpenCV相关API使用 图像二值化 1.二值图像 二值图像就是将灰度图转化成黑白图,没有灰,在一个值之前为黑,之后为白 2.二值化方法 全局阈值 对整幅图像都是用一个统一的阈值来进行二值化 局部阈值 像素的邻域块的像素值分布来确定该像素位置上的二值化阈值 3.OpenCV中图像二值化方法 二值化函数threshold 函数原型 关于常见的阈值使用方法如下表 OTSU(最大类间方差
快学Python
2021/08/09
8160
Python opencv图像处理基础总结(四) 模板匹配 图像二值化
模板匹配是一种最原始、最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识别对象物,这就是一个匹配问题。它是图像处理中最基本、最常用的匹配方法。模板匹配具有自身的局限性,主要表现在它只能进行平行移动,若原图像中的匹配目标发生旋转或大小变化,该算法无效。
叶庭云
2022/05/09
1.6K0
Python opencv图像处理基础总结(四) 模板匹配 图像二值化
【从零学习OpenCV 4】图像二值化
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。
小白学视觉
2019/11/27
1K0
【从零学习OpenCV 4】图像二值化
Python opencv图像处理基础总结(四) 模板匹配 图像二值化
模板匹配是一种最原始、最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识别对象物,这就是一个匹配问题。它是图像处理中最基本、最常用的匹配方法。模板匹配具有自身的局限性,主要表现在它只能进行平行移动,若原图像中的匹配目标发生旋转或大小变化,该算法无效。
叶庭云
2020/09/17
4.9K0
Python  opencv图像处理基础总结(四)  模板匹配  图像二值化
二值化算法OTSU源码解析
概述: 本文中小编将会跟大家分享一下OpenCV3.1.0中图像二值化算法OTSU的基本原理与源代码解析,最终还通过几行代码演示了一下如何使用OTSU算法API实现图像二值化。 一:基本原理 该方法是
OpenCV学堂
2018/04/04
2K0
二值化算法OTSU源码解析
一文搞懂图像二值化算法
传统的机器视觉通常包括两个步骤:预处理和物体检测。而沟通二者的桥梁则是图像分割(Image Segmentation)[1]。图像分割通过简化或改变图像的表示形式,使得图像更易于分析。
不脱发的程序猿
2021/05/08
3.4K0
一文搞懂图像二值化算法
Wellner 自适应阈值二值化算法
参考文档: Adaptive Thresholding for the DigitalDesk.pdf
用户1138785
2019/09/11
4.1K0
Wellner 自适应阈值二值化算法
opencv 5 -- 图像阈值
二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓
wust小吴
2019/07/08
8690
OpenCV与图像处理(十)
图像处理是利用计算机对图像进行去噪、增强、复原、重建、编码、压缩、几何变换、分割,提取特征等的理论、方法和技术。图像处理中,输入的是低质量的图像,输出的是改善质量后的图像。
Must
2020/07/27
1.4K0
有赞零售小票打印图片二值化方案
小票打印是零售商家的基础功能,在小票信息中,必然会存在一些相关店铺的信息。比如,logo 、店铺二维码等。对于商家来说,上传 logo 及店铺二维码时,基本都是彩图,但是小票打印机基本都是只支持黑白二值图打印。为了商家的服务体验,我们没有对商家上传的图片进行要求,商家可以根据实际情况上传自己的个性化图片,因此就需要我们对商家的图片进行二值图处理后进行打印。
有赞coder
2020/08/25
9270
有赞零售小票打印图片二值化方案
基于OpenCV的图像分割处理!
图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。它不仅可以极大的压缩数据量,而且也大大简化了分析和处理步骤,因此在很多情况下,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。
Datawhale
2020/07/09
3.6K0
基于OpenCV的图像分割处理!
系列4 | CV领域入门,马上开始进阶咯
元宵节看样子快到了,才立春、才春节、才开工,不知不觉到了元宵,估摸着2019确实过得挺快的!
计算机视觉研究院
2019/03/07
4790
系列4 | CV领域入门,马上开始进阶咯
CV学习笔记(十二):二值化操作
图像二值化就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。
云时之间
2020/03/19
9190
数字图像处理知识点总结概述
1.直方图:一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。
小白学视觉
2022/09/28
1.9K0
OTSU (大津法)阈值选择算法
大津法(OTSU)是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用。它是按图像的灰度特性,将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
为为为什么
2022/08/09
3.7K0
OTSU (大津法)阈值选择算法
OpenCV-Python学习(10)—— OpenCV 图像二值化处理(cv.threshold)
1. 学习目标 理解图像的分类,不同类型的图像的区别; 对图像进行二值化处理,对【 cv.threshold 】函数的理解。 2. 图像分类 2.1 不同类型图像说明 按照颜色对图像进行分类,可以分为二值图像、灰度图像和彩色图像。 二值图像:只有黑色和白色两种颜色的图像。 每个像素点可以用 0/1 表示,0 表示黑色,1 表示白色。 灰度图像:只有灰度的图像。 每个像素点用 8bit 数字 [0,255] 表示灰度,如:0 表示纯黑,255 表示纯白。 彩色图像:彩色图像通常 采用红色(R)、绿色(
Rattenking
2022/10/24
3.5K0
OpenCV-Python学习(10)—— OpenCV 图像二值化处理(cv.threshold)
CV学习笔记(十二):二值化操作
图像二值化就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。
云时之间
2020/03/06
1K0
没想到图像直方图有这么多应用场景
之前写过很多图像直方图相关的知识跟OpenCV程序演示,这篇算是把之前的都回顾一波。做好自己的知识梳理。
OpenCV学堂
2020/02/21
1.9K0
相关推荐
图像二值化方法汇总介绍
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 前言
  • 版本
  • 几种常用的优化方式
    • 提前使用 return 返回去除不必要的 else
    • 使用三目运算符
    • 使用枚举
    • 抽取条件判断作为单独的方法
    • 有时候 switch 比 if-else 更加合适
    • 策略模式 + 简单工厂模式
  • 如何优化开头的代码
  • 个人简介
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档