《Clean Code》

2023-09-18 21:51:36

整洁代码

一、命名

以业务为导向命名[operateMaxSaleQtyLogs] > 以技术命名[operateMaxSaleQtyLogList] > 随意命名 [logList]

1.1 变量

Rule 1. 【推荐】变量名称最好:名词、短语、形容词

Rule 2. 【推荐】不要在变量中包含多余的信息

badCase:User userWithNameAndAge = newUser()

Rule 3. 【推荐】避免误导

生成的单号,不要使用数字0、1和字母o、O、l、L

Rule 4. 【推荐】做有意义的区分:避免废话

product和productData、productInfo意思无区别

customer和customerData没区别

name和nameStr没区别

1.2 函数

Rule 1. 【推荐】函数名称动词 + 名词

Rule 2. 【推荐】函数长度

最好能20行以内

造成长函数的原因:

  • 把多个业务处理流程放在一个函数里实现;
  • 把不同层面的细节放到一个函数里实现。

Rule 3. 【推荐】只做一件事

每个函数一个抽象层级(锁库-较高抽象、查询算法或查档期-中间抽象、最大售卖量转换为字符串-低抽象)

反例:一个方法里,前20行代码在进行很复杂的基本价格计算,然后调用一个折扣计算函数,再调用一个赠品计算函数。
此时可将前20行也封装成一个价格计算函数,使整个方法在同一抽象层级上。

Rule 4. 【推荐】向下规则

每个函数后面,都紧跟着位于下一抽象层级的函数

    public void test(){
        //xxx
        a();
        //yyy
    }

    private void a() {
        //
        b();
        //
    }

    private void b() {
        //
    }

Rule 5. 【推荐】参数个数尽量小于3个

1)如果多个参数同属于一个对象,直接传递对象。

例外: 你不希望依赖整个对象,传播了类之间的依赖性。

2)将多个参数合并为一个新创建的逻辑对象。

例外: 多个参数之间毫无逻辑关联。

3)将函数拆分成多个函数,让每个函数所需的参数减少。

  1. 尤其是查询数据库时,将常用的查询参数封装为model。在构造查询条件的时候,if判空model中属性是否为null,不为null,则criteria

Rule 6. 【推荐】减少记忆参数顺序的负担

AssertEquals(expected,actual)==》 assertExpectedEqualsActual(expected,actual)

Rule 7. 【推荐】尽量减少重复的代码,抽取方法

超过5行以上重复的代码,都可以考虑抽取公用的方法。

Rule 8.【推荐】需要进行参数校验

执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,代价更大。

class A {
  void hello(List list);
  void hello(ArrayList arrayList);
}

List arrayList = new ArrayList();
a.hello(arrayList);//调用的是hello(List list),因为arrayList的定义类型是List

Rule 9.【推荐】不要返回null

如果你打算在方法中返回null,不如抛出异常,或者返回特例对象(Collections。emptylist()等)

Rule 10.【推荐】入参不要传递null

入参为null,也很容易npe

Rule 11.【推荐】先整体后细节

大部分人阅读代码的习惯是,先看此方法整体1、2、3做什么,然后再看1中具体细节

  • 重构前的代码
public void invest(long userId, long financialProductId) {
  Calendar calendar = Calendar.getInstance();
  calendar.setTime(date);
  calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
  if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
    return;
  }
  //...
}
  • 重构后的代码:提炼函数之后逻辑更加清晰

public void invest(long userId, long financialProductId) {
  if (isLastDayOfMonth(new Date())) { //先整体再细节
    return;
  }
  //...
}

public boolean isLastDayOfMonth(Date date) {
  Calendar calendar = Calendar.getInstance();
  calendar.setTime(date);
  calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
  if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
   return true;
  }
  return false;
}

1.3 类

Rule 1. 【推荐】命名使用名词、名词短语叠

避免使用动词(Manager、Processor)

Rule 2. 【推荐】字段未分组避免大类的产生、

可以将一个大类n多个字段,按照商品基本信息、档期信息、库存信息、其它信息等几个模块分组。

Rule 3. 【推荐】高内聚

类应该只有少数实体变量、类中方法操作的变量越多,类就越内聚。

大函数 -> 小函数(使用了大函数的4个变量)-> 将4个变量提升为类的实体变量 -> 丧失内聚(新增了4个只是为了少量函数而存在的实体变量)

-> 将这些想要共享某些实体变量的函数 和 实体,抽离为一个新的小类,这样就完成了大函数 到 小函数的拆分,同时类也符合高内聚

二、格式

Rule 1. 【推荐】加减空格,乘除不加空格

int result = temp - 2*a*b ; 

三、条件语句

Rule 1. 【推荐】少用if-else方式,多用哨兵语句式以减少嵌套层次

if (condition) {
  ...
  return obj;
}

// 接着写else的业务逻辑代码;

Rule 2.【推荐】减少使用取反的逻辑

不使用取反的逻辑,有利于快速理解。且大部分情况,取反逻辑存在对应的正向逻辑写法。

Rule 3.【推荐】能用while循环实现的代码,就不用do-while循环

四、对象和数据结构

Rule 1.【推荐】面向对象编程

eg1: 计算图形的面积

  • 面向对象编程

    // 正方形
    @Data
    public class Square {
        private Double side;
    }
    
    // 圆形
    @Data
    public class Circle {
        private Double r;
    }
    
    // 计算类
    public class Calculate {
    
        public double area(Object shape) {
    
            if (shape instanceof Square) {
                Square square = (Square) shape;
                Double side = square.getSide();
                return side * side;
            }
    
            if (shape instanceof Circle) {
                Circle circle = (Circle) shape;
                Double r = circle.getR();
                return Math.PI * r * r;
            }
            throw new NoSuchElementException();
        }
    }
    

    当新增三角形这种数据结构时,需要:添加三角形类、需要在计算类中新增if判断条件,违背了开闭原则

  • 面向对象编程

    // 接口定义方法:计算面积
    public interface Shape {
    
        /**
         * 计算图形的面积
         * @return 面积
         */
        public double area();
    }
    
    
    // 具体的正方形
    public class Square implements Shape{
        private Double side;
    
        @Override
        public double area() {
            return side * side;
        }
    }
    
    // 具体的圆形
    public class Circle implements Shape{
    
        private Double r;
    
        @Override
        public double area() {
            return Math.PI * r * r;
        }
    }
    

    当新增三角形这种数据结构时,需要:仅仅需要添加三角形实现类,实现接口重写area方法即可,符合开闭原则

eg2:计算不同等级用户对应的图书价格

  • 面向对象编程

    // 获取微信读书,不同书对于不同等级用户的价格
    public double getWeiXinReadBookPrice(final User user, final Book book) {
      double price = book.getPrice();
      switch (user.getLevel()) {
        case UserLevel.SILVER: //银
          return price * 0.9;
        case UserLevel.GOLD:  // 金
          return price * 0.8;
        default:
          return price;
      }
    }
    
    // 获取Kindle,不同书对于不同等级用户的价格
    public double getKindleBookPrice(final User user, final Book book) {
      double price = book.getPrice();
      switch (user.getLevel()) {
        case UserLevel.SILVER: //银
          return price * 0.95;
        case UserLevel.GOLD:   // 金
          return price * 0.85;
        default:
          return price;
      }
    }
    

    如果新增用户的Level:Plantinum铂金用户,则对应的书的具体价格又不一样,两个方法都要新增case,违背了开闭原则

  • 面向对象编程

    // 定义用户等级接口
    interface UserLevel {
      double getWeiXinReadBookPrice(Book book);
      double getKindleBookPrice(Book book);
    }
    
    // 白银用户,使用微信读书 和 Kindle读书,对应的书价
    class SilverUserLevel implements UserLevel {
      @Override
      public double getWeiXinReadBookPrice(final Book book) {
        return book.getPrice() * 0.9;
      }
      
      @Override
      public double getKindleBookPrice(final Book book) {
        return epub.getPrice() * 0.85;
      }
    }
    
    // 黄金用户,使用微信读书 和 Kindle读书,对应的书价
    class GoldUserLevel implements UserLevel {
      @Override
      public double getWeiXinReadBookPrice(final Book book) {
        return book.getPrice() * 0.8;
      }
      
      @Override
      public double getKindleBookPrice(final Book book) {
        return epub.getPrice() * 0.85;
      }
    }
    
    
    // 调用的时候,就不要使用Switch
    public double getWeiXinReadBookPrice(final User user, final Book book) {
      UserLevel level = user.getUserLevel()
      return level.getBookPrice(book);
    }
    

    如果新增用户的Level:Plantinum铂金用户,则直接新增铂金类,实现接口,重写两个方法即可,其它地方均无需改动,遵循开闭原则

更多推荐

【Spatial-Temporal Action Localization(二)】论文阅读2017年

文章目录1.ActionVLAD:Learningspatio-temporalaggregationforactionclassification[code](https://github.com/rohitgirdhar/ActionVLAD/)[](https://github.com/rohitgirdhar/

platform驱动模型

一、总线驱动模型1.概念linux中将一个挂载在总线上的驱动的驱动模型分为三部分:device、driver和bus。device是用来保存设备信息的对象,存放在内核中一个klist_device链表中进行管理。driver当前设备的驱动信息对象,存放在内核中一个klist_driver链表中进行管理。bus是当前设备

【Python从入门到进阶】36、Selenium 动作交互

接上篇《35、selenium基本语法学习》上一篇我们介绍了selenium的基本语法,包括元素定位以及访问元素信息的操作。本篇我们来学习selenium操作网页的动作内容。一、什么是selenium动作操作动作操作是指使用Selenium调用WebDriver执行与用户交互相关的动作,例如单击、右键单击、悬停、拖放等

Redis集群搭建

Redis集群搭建1、主从模式部署1.1环境准备IP主机名角色192.168.54.200mastermaster192.168.54.201slave1slave1192.168.54.202slave2slave21.2下载下载地址:http://download.redis.io/releases/这里选择下载:

全链路自动化测试

背景从SOA架构到现在大行其道的微服务架构,系统越拆越小,整体架构的复杂度也是直线上升,我们一直老生常谈的微服务架构下的技术难点及解决方案也日渐成熟(包括典型的数据一致性,系统调用带来的一致性问题,还是跨节点跨机房复制带来的一致性问题都有了很多解决方案),但是有一个环节我们明显忽略了。在现在的微服务架构趋势下,微服务在

微信小程序| 打造ChatGPT英语四六级背单词小程序

一、需求背景学英语,最大的痛苦莫过于背单词!不知道你平时都是用什么方式在背单词呢?硬啃单词书?字典?还是说各类的背单词APP来回跳转?不可否认的是,单词一两遍完全记不住,没有个三四五六七八遍,都很难在考场的卷子上认出他!所以,这次我们来做一个通关英语四六级的背单词神器,让他能够基于艾宾浩斯遗忘规律来辅助我们高效背单词。

数仓主题域和数据域、雪花模型,星型模型和星座模型

数仓模型和领域划分一、主题域和数据域的差别二、雪花模型,星座模型和星型模型一、主题域和数据域的差别明确数据域作为数仓搭建的重要一环,能够让数仓的数据便于管理和应用。数据域和主题域都是数据仓库中的重要概念,但含义略有不同,常常作为面试官的面试考点。数据域指的是特定的业务领域或是业务过程,如销售、采购、人力资源管理、财务等

前端需要知道的计算机网络知识----网络安全,自学网络安全,学习路线图必不可少,【282G】初级网络安全学习资源分享!

网络安全(英语:networksecurity)包含网络设备安全、网络信息安全、网络软件安全。黑客通过基于网络的入侵来达到窃取敏感信息的目的,也有人以基于网络的攻击见长,被人收买通过网络来攻击商业竞争对手企业,造成网络企业无法正常营运,网络安全就是为了防范这种信息盗窃和商业竞争攻击所采取的措施。随着互联网的高速发展,信

如何写一份出色的毕业设计任务书

title:如何写一份出色的毕业设计任务书date:2023-09-20毕业设计任务书是每个毕业生必须面对的关键文档。它不仅是你完成毕业设计的路线图,还是导师评估你工作的依据。因此,撰写一份清晰、详细且具体的任务书至关重要。本文将向你介绍如何编写一份出色的毕业设计任务书。1.确定项目背景和目的任务书的第一部分应该解释你

Mysql优化习惯|建表规约丶SQL规约丶索引规约

今天看到一个mysql规范,说mysql里面的字符集utf8不是真正的utf8(很感兴趣就去搜索了一下);真正的utf8字符集在mysql里面叫utf8mb4.感兴趣的自己可以去看下这个链接MySQL中的utf8并不是真正的UTF-8编码!!_mysql是真正utf-8_I'msureok!的博客-CSDN博客言归正传

06-Redis缓存高可用集群

上一篇:05-Redis高可用集群之水平扩展1.集群方案比较哨兵模式在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换

热文推荐