设计原则,编程规范的总结

  1. 1. 代码质量的评判标准
  2. 2. 面向对象
  3. 3. 设计原则
  4. 4. 相关的文章
  5. 5. 实战:ID生成器
    1. 5.1 原始的生成ID的代码
    2. 5.2 完善后的代码

本文作为一个对于整理过的设计原则和思想的总结,包括:

  • 面向对象
    • 封装、继承、抽象、多态
    • 面向对象编程 vs 面向过程编程
    • 面向对象分析、设计、编程
    • 接口 vs 抽象类
    • 基于接口而非实现编程
    • 多用组合少用继承
    • 贫血模式 vs 充血模式
  • 设计原则
    • 单一职责原则
    • 开闭原则
    • 里氏替换原则
    • 接口隔离原则
    • 依赖倒置原则
    • DRY
    • KISS
    • YAGNI
    • LOD
  • 规范与重构
    • 目的,对象,时机,方法
    • 单元测试和代码的可测试性
    • 大重构
    • 小重构

1. 代码质量的评判标准

  • 常用评价标准
    • 最常用
      • 可维护性
      • 可读性
      • 可扩展性
    • 其他
      • 灵活性
      • 简洁性
      • 可复用性
      • 可测试性
  • 如何写出高质量代码?
    • 设计思想
    • 设计原则
    • 设计模式
    • 编码规范
    • 重构技巧

2. 面向对象

  • 特性

    • 封装
      • 隐藏信息,数据访问保护
    • 继承
      • is a
    • 多态
      • 子类可以替代父类的模式
      • 在实际代码运行当中,通过调用子类的方法来实现
    • 抽象
      • 隐藏类的具体实现方法
      • 使得修改实现不需要改变定义
  • 面向对象设计 – 如何设计出具体的类

    • 划分职责
    • 定义类及其属性和方法
    • 定义类和类之间的交互关系
    • 将类组装起来并提供执行入口
  • 接口 vs 抽象类

    • 接口

      • 对方法的抽象
      • 是一种has a的关系
      • 表示具有某一组行为特性
      • 为了解决解耦问题,隔离接口和具体实现,提高代码扩展性
    • 抽象类

      • 对成员变量和方法的抽象
      • 是一种is a的关系
      • 为了解决代码复用的问题
  • 贫血模型 vs 充血模型

    • MVC 贫血模型
    • 充血模型的设计
      • 与贫血模型的区别在于Service层
      • 在基于充血模型的开发模式下,将service类中的业务逻辑移动到一个充血的domain领域模型当中
      • 让Service类的实现依赖这个domain类

3. 设计原则

  • 单一职责原则

    • 一个类只负责一个职责或者功能
  • 开闭原则

    • 对扩展开放,对修改关闭
      • 添加一个新的功能,应该是通过在已有的代码基础上扩展代码(新增模块,类,方法,属性),而非修改已有的代码的方式来完成的
      • 指的是以最小的修改代码的代价来完成新功能的开发
  • 里氏替代原则

    • 子类对象能够替代程序当中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。
    • 理解 Design by contract 按照协议来设计
    • 父类定义函数的约定/协议
    • 子类可以改变函数的内部实现逻辑,但不能改变函数的原有约定
      • 约定包括
        • 函数声明要实现的功能
        • 对输入 输出 异常的约定
        • 注释中罗列的特殊说明
  • 接口隔离原则

    • 客户端不应该强迫依赖它不需要的接口
      • 将接口理解为一组接口集合
        • 如果部分接口只被部分调用者使用,应该将这部分接口隔离起来,单独给他们使用
      • 理解为单个API接口或函数
        • 部分调用者只需要函数的部分功能,那我们就应该将函数拆分为粒度更细的多个函数,让调用者只依赖它需要的那个细粒度的函数
      • 理解为OOP中的接口
        • 接口的设计需要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数
  • YAGNI - you ain’t gonna need it

  • LOD - 高内聚,低耦合

  • 迪米特法则

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

4. 相关的文章

  1. 架构学习-general
  2. 架构学习-原则
  3. 架构学习-可扩展架构模式
  4. 架构学习-复杂度来源
  5. 架构学习 - 实战
  6. 架构学习 - 架构设计文档模板
  7. 架构学习-架构设计流程
  8. 架构学习-高可用架构模式
  9. 架构学习-高性能架构模式
  10. 基于充血模型的DDD开发模型
  11. SOLID-单一职责原则
  12. SOLID - 开闭原则
  13. SOLID - 里氏替换原则
  14. SOLID - 接口隔离原则
  15. SOLID - 依赖反转原则
  16. KISS and YAGNI原则
  17. DRY 原则
  18. 迪米特法则 (LOD) — 高内聚,低耦合
  19. 应用设计 Practice
  20. 提高代码质量的Tips

5. 实战:ID生成器

使用ID来做服务内部的请求追踪,因为在日志文件当中,不同请求的日志是会交织到一起的。我们需要使用ID来标识哪些日志属于同一个请求。

因此我们需要做的事情就是给每个请求分配一个唯一的ID,并且保存在请求的上下文当中。Java当中可以将ID存储在ThreadLocal当中,或者使用Slf4j的MDC(Mapped Diagnostic Contexts)来实现。每次打印日志的时候,我们就可以从请求上下文当中取出请求ID,跟日志一块输出。

5.1 原始的生成ID的代码

public class IdGenerator {
  private static final Logger logger = LoggerFactory.getLogger(IdGenerator.class);

  public static String generate() {
    String id = "";
    try {
      String hostName = InetAddress.getLocalHost().getHostName();
      String[] tokens = hostName.split("\\.");
      if (tokens.length > 0) {
        hostName = tokens[tokens.length - 1];
      }
      char[] randomChars = new char[8];
      int count = 0;
      Random random = new Random();
      while (count < 8) {
        int randomAscii = random.nextInt(122);
        if (randomAscii >= 48 && randomAscii <= 57) {
          randomChars[count] = (char)('0' + (randomAscii - 48));
          count++;
        } else if (randomAscii >= 65 && randomAscii <= 90) {
          randomChars[count] = (char)('A' + (randomAscii - 65));
          count++;
        } else if (randomAscii >= 97 && randomAscii <= 122) {
          randomChars[count] = (char)('a' + (randomAscii - 97));
          count++;
        }
      }
      id = String.format("%s-%d-%s", hostName,
              System.currentTimeMillis(), new String(randomChars));
    } catch (UnknownHostException e) {
      logger.warn("Failed to get the host name.", e);
    }

    return id;
  }
}
  • 上述代码存在的问题
    • static 方法可测试性太低
    • generate函数的代码实现依赖运行环境,时间函数以及随机函数,本身的可测试性也不强
    • 随机字符串生成代码难以看懂
    • 有太多的魔法数,需要告诉读代码的人这些都是什么意思才可以的

5.2 完善后的代码

public interface IdGenerator {
  String generate();
}

public interface LogTraceIdGenerator extends IdGenerator {
}

public class RandomIdGenerator implements IdGenerator {
  private static final Logger logger = LoggerFactory.getLogger(RandomIdGenerator.class);

  @Override
  public String generate() {
    String substrOfHostName = getLastfieldOfHostName();
    long currentTimeMillis = System.currentTimeMillis();
    String randomString = generateRandomAlphameric(8);
    String id = String.format("%s-%d-%s",
            substrOfHostName, currentTimeMillis, randomString);
    return id;
  }

  private String getLastfieldOfHostName() {
    String substrOfHostName = null;
    try {
      String hostName = InetAddress.getLocalHost().getHostName();
      String[] tokens = hostName.split("\\.");
      substrOfHostName = tokens[tokens.length - 1];
      return substrOfHostName;
    } catch (UnknownHostException e) {
      logger.warn("Failed to get the host name.", e);
    }
    return substrOfHostName;
  }

  private String generateRandomAlphameric(int length) {
    char[] randomChars = new char[length];
    int count = 0;
    Random random = new Random();
    while (count < length) {
      int maxAscii = 'z';
      int randomAscii = random.nextInt(maxAscii);
      boolean isDigit= randomAscii >= '0' && randomAscii <= '9';
      boolean isUppercase= randomAscii >= 'A' && randomAscii <= 'Z';
      boolean isLowercase= randomAscii >= 'a' && randomAscii <= 'z';
      if (isDigit|| isUppercase || isLowercase) {
        randomChars[count] = (char) (randomAscii);
        ++count;
      }
    }
    return new String(randomChars);
  }
}

//代码使用举例
LogTraceIdGenerator logTraceIdGenerator = new RandomIdGenerator();

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 stone2paul@gmail.com

文章标题:设计原则,编程规范的总结

文章字数:1.8k

本文作者:Leilei Chen

发布时间:2020-06-07, 11:12:00

最后更新:2020-06-10, 21:21:56

原始链接:https://www.llchen60.com/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99%EF%BC%8C%E7%BC%96%E7%A8%8B%E8%A7%84%E8%8C%83%E7%9A%84%E6%80%BB%E7%BB%93/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏