【Elegant Programming (优雅的编程)】如何用合理的封装优雅的化解三层以上的 if-else ?

news2024/10/2 10:36:09

在这里插入图片描述

👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主

⛪️ 个人社区:个人社区
💞 个人主页:个人主页
🙉 专栏地址: ✅ Java 中级
🙉八股文专题:剑指大厂,手撕 Java 八股文

文章目录

      • 1. 写下前面
      • 2. 如何用合理的封装优雅的化解三层以上的 if-else ?
      • 3. 写在最后

1. 写下前面

今天跟大家分享一个 Githup 的项目,这个项目叫:Elegant Programming (优雅的编程),这个项目目前在持续更新中。
Elegant Programming (优雅的编程) 的 Githup 链接:https://github.com/pydlove/ElegantProgramming?tab=readme-ov-file

Elegant Programming 是分享如何将代码写的更加优雅,代码不仅是程序运行的,更是人读的。既然是人读的,那么我就应该让它可读性更强一点。这个项目中所有的案例都是我平时工作中的积累,也没有刻意想要系统化的整理这种编程技巧,也是想到点就写一点。但是我保证你一定能有所收获。

今天我们分享 Elegant Programming 中的一个案例:如何用合理的封装优雅的化解三层以上的 if-else ?

接下来我们直接进入正文。

2. 如何用合理的封装优雅的化解三层以上的 if-else ?

首先看需求介绍:

package com.pany.camp.example.case6;

import com.pany.camp.example.case4.main.ExampleHandler;
import com.pany.camp.example.case4.main.GraceExampleHandler;

/**
 *
 * @description:  ParamExample
 * @copyright: @copyright (c) 2022
 * @company: aiocloud
 * @author: panyong
 * @version: 1.0.0
 * @createTime: 2024-07-29 21:39
 */
public class ThreeNestedIfElseExample {

    public static void main(String[] args) {

        // 主题:如何用合理的封装优雅的化解三层以上的 if-else ?
        //
        // 首先我先说下需求:这一次我们需要做一个心跳检测的服务,大致步骤如下:
        // 1、是否开启心跳检测?
        // 2、从 redis 上获取搜索的节点,然后对获取的结果进行判断
        // 3、遍历所有节点,针对每个节点做心跳检测
        // 4、心跳检测分为两个检测方式:主观检测 + 客观检测
        //
        // 基于这个需求,分别看下面两种实现,在代码我有明确指明哪些层是可以使用封装来减少 if-else 嵌套的层数,
        // 并且通过封装让代码可读性更强。
        // 错误案例 ExampleHandler().handle()
        // 正确案例 GraceExampleHandler().handle()
        new ExampleHandler().handle();

        new GraceExampleHandler().handle();
    }
}

然后我们先看错误案例,这个错误案例也是我在这么多年工作中经常见到的,很多写了三五年代码的,也可能会这样写;

package com.pany.camp.example.case6.main;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.pany.camp.common.redis.RedisKey;
import com.pany.camp.common.redis.RedisNameSpace;
import com.pany.camp.common.redis.RedisOperate;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Objects;

/**
 *
 * @description:  ExampleHandler
 * @copyright: @copyright (c) 2022 
 * @company: aiocloud
 * @author: panyong
 * @version: 1.0.0 
 * @createTime: 2024-08-03 16:56
 */
@Slf4j
public class ExampleHandler {

    private static final long HEARTBEAT_TIMEOUT = 1000 * 60 * 5;

    public void handle() {

        // 假设我们这里要做心跳检测服务
        if (isOpenHeartbeatCheck()) {

            // 首先获取所有节点
            Object hostObj = RedisOperate.get(new RedisKey(RedisNameSpace.SYSTEM_HEARTBEAT_HOST));
            if (Objects.isNull(hostObj)) {
                log.error("system heartbeat host not existed, please check in redis");
                return;
            }

            // 遍历节点检查心跳
            List<String> hostNames = JSONObject.parseObject(hostObj.toString(), new TypeReference<List<String>>() {});
            for (String hostName : hostNames) {

                // 主观检查:如果没有查看到注册心跳,证明可能下线了
                Object hostTimeObj = RedisOperate.get(new RedisKey(RedisNameSpace.SYSTEM_HEARTBEAT_TIME, hostName));
                if (Objects.isNull(hostTimeObj)) {
                    log.error("system heartbeat time, host: {} not report time for redis", hostName);

                    // 客观判断:如果心跳超时了,那么我们在请求下节点的接口,根据接口是否响应,来判断节点是否还存活
                    if (!requestNodeAlive(hostName)) {

                        // 确认节点下线了,做一些善后的处理,如:故障转移,通知其他节点,通知用户等
                        AftermathHandler.handle(hostName);
                    }

                } else {

                    // 主观检查:首先基于时间戳判断,是否上报的心跳超时了
                    long hostTime = Long.parseLong(hostTimeObj.toString());
                    if (System.currentTimeMillis() - hostTime > HEARTBEAT_TIMEOUT) {

                        // 客观判断:如果心跳超时了,那么我们在请求下节点的接口,根据接口是否响应,来判断节点是否还存活
                        if (!requestNodeAlive(hostName)) {

                            // 确认节点下线了,做一些善后的处理,如:故障转移,通知其他节点,通知用户等
                            AftermathHandler.handle(hostName);
                        }
                    }
                }
            }
        }
    }

    private boolean requestNodeAlive(String hostName) {
        return httpRequestByHostName(hostName);
    }

    private boolean httpRequestByHostName(String hostName) {

        // 假设这里是通过 http 请求来判断节点是否还存活
        return false;
    }

    private boolean isOpenHeartbeatCheck() {

        // 假设这里是从环境配置中读取是否开启心跳检测
        return getFromApplicationConfig();
    }

    private Boolean getFromApplicationConfig() {
        return true;
    }
}

阅读完错误的案例,接下来看正确的案例,如何用封装简化逻辑?

package com.pany.camp.example.case6.main;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.pany.camp.common.redis.RedisKey;
import com.pany.camp.common.redis.RedisNameSpace;
import com.pany.camp.common.redis.RedisOperate;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Objects;

/**
 *
 * @description:  GraceExampleHandler
 * @copyright: @copyright (c) 2022 
 * @company: aiocloud
 * @author: panyong
 * @version: 1.0.0 
 * @createTime: 2024-08-03 16:56
 */
@Slf4j
public class GraceExampleHandler {

    private static final long HEARTBEAT_TIMEOUT = 1000 * 60 * 5;

    public void handle() {

        // 假设我们这里要做心跳检测服务
        if (isOpenHeartbeatCheck()) {

            // (这里使用封装)如果开启心跳检测,那么我们开始心跳检测的处理
            doHeartbeatCheck();
        }
    }

    private void doHeartbeatCheck() {

        // 首先获取所有节点
        Object hostObj = RedisOperate.get(new RedisKey(RedisNameSpace.SYSTEM_HEARTBEAT_HOST));
        if (Objects.isNull(hostObj)) {

            log.error("system heartbeat host not existed, please check in redis");
            return;
        }

        // 遍历节点检查心跳
        List<String> hostNames = JSONObject.parseObject(hostObj.toString(), new TypeReference<List<String>>() {});
        for (String hostName : hostNames) {

            // (这里使用封装)针对选中的或者单个的主机节点进行心跳检测
            if (checkIsOffline(hostName)) {

                // (这里使用封装)确认节点下线了,做一些善后的处理,如:故障转移,通知其他节点,通知用户等
                AftermathHandler.handle(hostName);
            }
        }
    }

    private boolean checkIsOffline(String hostName) {

        // 主观检查:首先基于时间戳判断,是否上报的心跳超时了
        Object hostTimeObj = RedisOperate.get(new RedisKey(RedisNameSpace.SYSTEM_HEARTBEAT_TIME, hostName));
        if (Objects.isNull(hostTimeObj)) {
            log.error("system heartbeat time, host: {} not report time for redis", hostName);

            return true;
        }

        long hostTime = Long.parseLong(hostTimeObj.toString());

        // 主观检查:首先基于时间戳判断,是否上报的心跳超时了 +  客观判断:如果心跳超时了,那么我们在请求下节点的接口,根据接口是否响应,来判断节点是否还存活
        if ((System.currentTimeMillis() - hostTime > HEARTBEAT_TIMEOUT) && requestNodeAlive(hostName))  {
            return true;
        }

        return false;
    }

    private boolean requestNodeAlive(String hostName) {
        return httpRequestByHostName(hostName);
    }

    private boolean httpRequestByHostName(String hostName) {

        // 假设这里是通过 http 请求来判断节点是否还存活
        return false;
    }

    private boolean isOpenHeartbeatCheck() {

        // 假设这里是从环境配置中读取是否开启心跳检测
        return getFromApplicationConfig();
    }

    private Boolean getFromApplicationConfig() {
        return true;
    }
}

3. 写在最后

在工作中,我会因为多了一个空格和一个换行而去修改。工作中大家写代码还是要有一定追求的,我觉得不应该只是为了完成这个任务,获取的能力提升还是自己的。

然后更多的编程技巧可以去 Githup上看这个开源项目。
链接:https://github.com/pydlove/ElegantProgramming?tab=readme-ov-file

精彩专栏推荐订阅:在下方专栏👇🏻
✅ 2023年华为OD机试真题(A卷&B卷)+ 面试指导
✅ 精选100套 Java 项目案例
✅ 面试需要避开的坑(活动)
✅ 你找不到的核心代码
✅ 带你手撕 Spring
✅ Java 初阶

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1979282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构与算法 - 二叉树

1. 概述 二叉树是这么一种树状结构&#xff1a;每个节点最多有两个孩子&#xff0c;左孩子和右孩子 完全二叉树&#xff1a;是一种二叉树结构&#xff0c;除了最后一层以外&#xff0c;每一层都必须填满&#xff0c;填充时要遵循从左到右 平衡二叉树&#xff1a;是一种二叉树…

基础算法之模拟

1P1093 [NOIP2007 普及组] 奖学金 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1093https://www.luogu.com.cn/problem/P1093 #include<iostream> #include<algorithm> using namespace std; struct stu {int num;//编号int c…

尚品汇-首页三级分类实现-nginx静态代理生成的静态页面(二十六)

目录&#xff1a; &#xff08;1&#xff09;问题详解 &#xff08;2&#xff09;首页商品分类实现 &#xff08;3&#xff09;修改web-all模块 &#xff08;4&#xff09;页面渲染 &#xff08;1&#xff09;问题详解 &#xff08;2&#xff09;首页商品分类实现 前面做了…

【书生大模型实战营(暑假场)】入门任务三 Python 关卡

入门任务二 Python 关卡 参考&#xff1a; 教程任务 1 闯关任务 1.1 使用 Python 实现 wordcount import stringdef wordcount(text):# 去除标点符号text text.translate(str.maketrans(, , string.punctuation))# 转换为小写text text.lower()# 分割字符串成单词列表wo…

CH571F蓝牙orUSB摇杆鼠标

演示视频&#xff1a; 短视频刷个爽 程序基本上是基于官方的例程上改的&#xff0c;用到的例程有&#xff1a;蓝牙的HID_Mouse,USB的CompoundDev&#xff0c;还有ADC&#xff0c;按键中断。 主要原理 就是ADC采集采集摇杆电压&#xff0c;通过蓝牙HID或者USB的HID发送给电脑或…

文心一言 VS 讯飞星火 VS chatgpt (317)-- 算法导论22.3 9题

九、请给出如下猜想的一个反例&#xff1a;如果有向图G包含一条从结点u到结点v的路径&#xff0c;则任何对图G的深度优先搜索都将导致v.d⩽u.f。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 首先&#xff0c;我们需要澄清问题中的几个关键点。在图的深度优先…

想做抖音短视频,视频素材去哪里找啊?

各位抖音上的短视频创作者们&#xff0c;是否曾幻想过自己的作品能够在全网爆火&#xff0c;却常因为缺少那些能够让视频更加生动的素材而感到困扰&#xff1f;不用担心&#xff0c;今天我要为大家介绍几个优秀的视频素材网站&#xff0c;让你的抖音之路顺风顺水&#xff01; …

Linux系统中的高级用户空间与内核空间交互技术

Linux作为一种开源操作系统&#xff0c;具有良好的稳定性、安全性和自定制性&#xff0c;因而在各种设备和场景中得到广泛应用。作为Linux系统的核心组成部分&#xff0c;内核空间与用户空间交互技术对系统性能和功能扩展起着关键作用。本文将深入探讨Linux系统中的高级用户空间…

Vue Vine:带给你全新的 Vue 书写体验!

你好&#xff0c;我是 Kagol&#xff0c;个人公众号&#xff1a;前端开源星球。 上个月和 TinyVue 的小伙伴们一起参加了 VueConf 24 大会&#xff0c;有幸认识沈青川大佬&#xff0c;并了解了他的 Vue Vine 项目&#xff0c;Vue Vine 让你可以在一个文件中通过函数方式定义多…

系统化学习 H264视频编码(05)码流数据及相关概念解读

说明&#xff1a;我们参考黄金圈学习法&#xff08;什么是黄金圈法则?->模型 黄金圈法则&#xff0c;本文使用&#xff1a;why-what&#xff09;来学习音H264视频编码。本系列文章侧重于理解视频编码的知识体系和实践方法&#xff0c;理论方面会更多地讲清楚 音视频中概念的…

Nginx进阶-常见配置(二)

一、nginx 日志配置 nginx 日志介绍 nginx 有一个非常灵活的日志记录模式,每个级别的配置可以有各自独立的访问日志, 所需日志模块 ngx_http_log_module 的支持&#xff0c;日志格式通过 log_format 命令来定义&#xff0c;日志对于统计和排错是非常有利的&#xff0c;下面总…

【TwinCAT3教程】TwinCAT3 PLC 简单程序编写与调试

一、PLC 简单程序编写 1.1 新建TwinCAT3项目 (1)打开 TwinCAT 3,点击 New TwinCAT Project 新建 TC3 项目。 (2)选择 TwinCAT Project,输入项目名称和项目保存路径,然后点击确定。 1.2 添加PLC项目 1.2.1 步骤 (1)在树形资源管理器右键点击 PLC,选择 添加新项 新…

STM32F28335实验:继电器

继电器控制电机&#xff1a; 5s启动 5s停止 循环 管脚图&#xff1a; 管脚用的是GPIO15 驱动&#xff1a; beep.c /** leds.c** Created on: 2024年8月2日* Author: Administrator*/#include<relay.h>/***************************************************…

【算法设计题】查找给定结点的双亲结点(二叉树),第3题(C/C++)

目录 第3题 查找给定结点的双亲结点&#xff08;二叉树&#xff09; 得分点&#xff08;必背&#xff09; 题解 定义函数和初始化变量&#xff1a; 处理特殊情况&#xff1a; 遍历树&#xff1a; 中序遍历左子树&#xff1a; 处理右子树&#xff1a; 返回结果&#x…

LSTM实战之预测股票

&#x1f4c8; 用PyTorch搭建LSTM模型&#xff0c;轻松预测股票价格&#xff01;&#x1f680; Hey小伙伴们&#xff0c;今天给大家带来一个超级实用的项目教程——如何用PyTorch和LSTM模型来预测股票价格&#xff01;&#x1f31f; &#x1f50d; 项目背景 我们都知道股市是…

《Unity3D网络游戏实战》学习与实践--制作一款大乱斗游戏

角色类 基类Base Human是基础的角色类&#xff0c;它处理“操控角色”和“同步角色”的一些共有功能&#xff1b;CtrlHuman类代表“操控角色”​&#xff0c;它在BaseHuman类的基础上处理鼠标操控功能&#xff1b;SyncHuman类是“同步角色”类&#xff0c;它也继承自BaseHuman&…

MySQL的数据结构B+tree以及SQL优化

首先呢&#xff0c;我们知道MySQL的数据结构为Btree,那么其结构究竟是什么样的&#xff0c;为什么选择Btree&#xff0c;而不选择Btree。下面我们从其结构分析 1.Btree平衡多路查找树 B-tree结构的数据可以让系统高效的找到数据所在的磁盘块。为了描述B-Tree,首先定义一条记录…

入门mem0.NET

入门mem0.NET 安装包 如果你的项目使用了EntityFrameworkCore,那么你可以跟随这个教程走 <ItemGroup><PackageReference Include"mem0.NET" Version"0.1.7" /><PackageReference Include"mem0.NET.Qdrant" Version"0.1.7…

云动态摘要 2024-08-04

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 数据库上云优选 阿里云 2024-07-04 RDS、PolarDB、Redis、MongoDB 全系产品新用户低至首年6折起&#xff01; [免费体验]智能助手ChatBI上线 腾讯云 2024-07-02 基于混元大模型打造&…

java之IO篇——File、字节流、字符流

前言 IO流是用于读写文件中的数据&#xff0c;要读写文件之前可以创建文件获取文件对象再创建IO流&#xff0c;正文会先介绍File类&#xff0c;通过File类的构造方法获取文件的对象&#xff0c;创建文件或目录以及File类的一些方法获取文件对象的属性。后面还介绍了相关的IO流体…