松花皮蛋的黑板报
  • 分享在京东工作的技术感悟,还有JAVA技术和业内最佳实践,大部分都是务实的、能看懂的、可复现的

扫一扫
关注公众号

设计模式学习分享

博客首页文章列表 松花皮蛋me 2020-02-10 19:49

1、如何评价代码质量的高低


最常用到的几个评判代码质量的标准是:可维护性、可读性、可扩展性、灵活性、简洁性、可复用性、可测试性。

  • (1)、可维护性:是否能在不破坏原有代码设计、不引入新的BUG的情况下,能够快速地修改或者添加代码;
  • (2)、可读性:代码是否符合编码规范、命令是否达意、注释是否详尽等等;
  • (3)、可扩展性:代码是否可以通过预留的功能扩展点来扩充功能,而不用改动大量的原始代码;
  • (4)、灵活性:易扩展、易复用、易用;简洁性:KISS原则,尽量保证代码简单;

2、抽象类与接口的应用场景区别


如果要表示一种is-a的关系,并且是为了解决代码复用问题,就使用抽象类。如果要表示一种has-a的关系,并且为了解决抽象而非代码复用问题,就使用接口。

3、基于接口而非实现编程(基于抽象而非实现编程)


做软件设计的时候要有抽象意识、封装意识、接口意识,不要暴露任何实现细节,保证上下游调用稳定性,降低耦合性。

4、多用组合少用继承


利用组合、接口、委托,解决层次过深、过复杂的继承关系,避免影响代码的可维护性。

5、常见的不满足单一职责原则的设计

  • (1)、类中大量的方法都是集中操作类中的某几个属性;
  • (2)、类中的代码行数、属性过多;
  • (3)、类依赖的其他类过多;
  • (4)、私有方法过多;
  • (5)、比较难给类起一个合适的名字;

6、常见的违背里氏替换原则的设计

  • (1)、子类违背父类注释中所罗列的任何特殊说明;
  • (2)、子类违背父类声明要实现的功能;
  • (3)、子类违背父类对输入、输出、异常的约定;

7、开闭原则


尽量让修改操作更集中、更少、更上层。

8、接口隔离原则


接口隔离原则提供了一种判断接口是否满足单一职责原则的方法。如果调用者只使用部分接口或者接口的部分功能,那接口的设计就不够职责单一。

9、依赖注入


依赖注入是一种具体的编程技巧,关注的是对象创建与类之前的关系,目的是提高代码的扩展性,我们可以灵活地替换依赖的类。实际上依赖注入和基于接口而非实现编程都是基于开闭原则思路的。

10、如何写出满足KISS原则的代码

  • (1)、不要过度优化;
  • (2)、不要使用同事可能不懂的技术来实现代码;
  • (3)、不要重复造轮子,减少维护成本;

11、如何提高代码的可复用性


功能语义重复和代码执行重复其实都是违反DRY原则的,那如何提高代码的可复用性呢?

  • (1)、减少代码耦合;
  • (2)、满足单一职责原则;
  • (3)、模块化;
  • (4)、业务与非业务逻辑分离;
  • (5)、通用代码下沉;
  • (6)、应用模板等设计模式;

12、迪米特法则


不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。

13、代码分层的作用


代码分层的作用有:代码复用、隔离变化、隔离关注点、提供可测性、应对系统的复杂性。
其实编程就是一个拼插积木的过程。系统划分成若干个层次,每一层专注解决某个领域的问题。大问题分解成若干个子问题,如果子问题还没有直接解决,则继续分解成子子问题,直到可以直接解决的程序。

14、重构思绪


一定要建立持续重构意识,把重构作为开发必不可少的部分,融入到日常开发中。

15、常见的测试不友好的代码有下面五种

  • (1)、代码中包含未决行为逻辑;
  • (2)、滥用可变全局变量;
  • (3)、滥用静态方法;
  • (4)、使用复杂的继承关系;
  • (5)、高度耦合的代码;

16、如何通过封装、抽象、模块化、中间层等解耦代码?


单一职责原则、基于接口而非实现编程、依赖注入、多用组合少用继承、迪米特法则等。当然还有一些设计模式,比如观察者模式。

17、让你快速地改善代码质量的20条编程规范

  • (1)、关于命名,命名的关键是能准确达意。
  • (2)、关于注释,注释的内容包括做什么、为什么、怎么做、如何用,但是注释有一定的维护成本,一般都是靠好的命名、提炼函数、解释性变量、总结性注释来提供代码可读性。
  • (3)、类内成员的排列顺序。先写成员变量后写函数,并且按照作用域大小依次排列,也可以把有调用关系的函数放在一块。

18、如何发现代码质量问题,常规checklist

  • (1)、目录设置是否合理、模块划分是否清晰、代码结构是否满足”高内聚、松耦合”?
  • (2)、是否满足经典的设计原则和设计思想(SOLID\DRY\KISS\YAGNI\LOD等)?
  • (3)、设计模式是否应用得当?
  • (4)、是否有过度设计?
  • (5)、代码是否容易扩展?如果要添加新功能,是否容易实现?
  • (6)、代码是否可复用?是否可以复用已有的项目代码或者类库?是否有重复造轮子?
  • (7)、代码是否易测试?单元测试是否全面覆盖各种正常和异常的情况?
  • (8)、代码是否易读?
  • (9)、是否符合编码规范(比如代码风格)?

19、如何发现代码质量问题,业务需求checklist

  • (1)、代码是否实现了预期的业务需求?
  • (2)、逻辑是否正常?
  • (3)、是否处理了各种异常情况?
  • (4)、日记打印是否得当?是否方便debug排查问题?
  • (5)、接口是否易用?是否支持幂等、事务等?
  • (6)、代码是否存在并发问题?是否线程安全?
  • (7)、性能是否有优化空间?比如SQL\算法是否可以优化?
  • (8)、是否有安全漏洞?比如输入输出校验是否全面?

20、程序出错该返回啥?错误码、NULL值、空对象、异常对象?


对于查找函数,数据不存在并非是异常情况,它是一种正常行为,所以返回不存在语义的NULL值比返回异常更加合理。


对于函数抛出的异常,我们有三种处理方法:直接吞掉、直接往上抛出、包裹成新的异常抛出。如果调用者关心该异常就往上抛出。如果向上抛出的异常和业务概率没有太大相关性,或者暴露过多实现细节,或者调用者看到这个异常,并不能理解异常到底代表了什么,该如何处理,那就必须包裹成新的异常。


如果函数是private类私有的,只在类内部被调用,完全在自己的掌控中,不需要判断非空。否则,为了尽可能提高代码的健壮性,就需要做NULL值或空字符串的判断。

21、单例模式


单例模式通常用来避免资源访问冲突和表示业务概念的全局唯一性。但是也存在一些缺点,比如对OOP特性的支持不友好、隐藏类之间的依赖关系、对代码的扩展性不友好(如资源池设计动态修改参数)、对代码的可测性不友好。基于此,我们可以使用工厂模式、IOC容器等解决方案替换单例模式。


单例中对象的唯一性的作用范围内是进程内的。更严格地说,对于Java语言来说,单例类对象的唯一性的作用范围是类加载器。因为在Java中,两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它的类加载器不同,那这两个类就必定不相等。


其他单例模式的问题:如何线程唯一的单例?可以利用Java语言本身的ThreadLocal工具类。如何实现集群环境下的单例?将单例对象序列化存储到外部空间,使用时进行反序列化。如何实现一个多例模式?可以利用ConcurrentHashMap的putIfAbsent方法。多例模式有点类似枚举单例和享元模式。

22、工厂模式


当创建逻辑比较复杂,是一个”大工程”的时候,我们就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。


判断要不要使用工厂模式的参考指标:封装变化(创建逻辑的变更对调用者透明)、代码复用、隔离复杂性、控制复杂度。


23、DI容器


配置解析、对象创建、对象生命周期管理、提供执行入口。


24、建造者模式


针对类属性有默认值、不可变性、有依赖关系、有约束条件的复杂型对象,通常使用建造者模式来构建,然后在build方法中进行合法性校验。

持续更新中……。更多精彩,欢迎关注公众号:松花皮蛋的黑板报