JAVA设计模式前篇-6大设计原则
1:单一职责原则(Single Responsibility Principle)
概念描述:一个类只负责一个功能领域的相应职责,即一个类的变更原因只会有一个。
public Result<Boolean> transfer(Long sourceUserId, String targetAccountNumber, BigDecimal targetAmount, String targetCurrency) {
// 1. 从数据库读取数据
AccountDO sourceAccountDO = accountDAO.selectByUserId(sourceUserId);
AccountDO targetAccountDO = accountDAO.selectByAccountNumber(targetAccountNumber);
// 2. 业务参数校验
if (!targetAccountDO.getCurrency().equals(targetCurrency)) {
throw new InvalidCurrencyException();
}
// 3. 获取外部数据,获取雅虎的汇率转换
BigDecimal exchangeRate = BigDecimal.ONE;
if (sourceAccountDO.getCurrency().equals(targetCurrency)) {
exchangeRate = yahooForex.getExchangeRate(sourceAccountDO.getCurrency(), targetCurrency);
}
BigDecimal sourceAmount = targetAmount.divide(exchangeRate, RoundingMode.DOWN);
// 4. 更新到数据库
accountDAO.update(sourceAccountDO);
accountDAO.update(targetAccountDO);
// 5. 发送审计消息
String message = sourceUserId + "," + targetAccountNumber + "," + targetAmount + "," + targetCurrency;
kafkaTemplate.send(TOPIC_AUDIT_LOG, message);
return Result.success(true);
}
以上是一个普通的业务类,主要功能包含数据库查询更新,参数校验,调用外部服务雅虎的汇率转换功能以及发送审计消息等,那么就单一职责原则来看,当前类变化的原因有哪些?
1. 校验规则的改变
2. 雅虎汇率服务可能会替换成其他的服务
3. 消息中间件的替换
4. 这里数据库层暂时可以忽略,底层数据库的变更可能会被屏蔽掉
当前类作为一个业务类,变更的原因应该只有一个,就是业务规则变更,可能需要添加/减少一些流程,而不是受到其他因素的影响。
2:里氏替换原则(Liskov Substitution Principle)
概念描述:子类型必须能够替换掉它们的父类型。
正常举例:父类是动物,并且可以发出声音,子类的Dog和Cat继承父类,并重写了makeSound(),无论是使用父类还是子类,都可以发出声音,这是没有问题的。
违反举例:父类是鸟,具有一个飞的功能,鹰和鸵鸟继承自父类,但是鸵鸟不会飞,调用飞方法就会出现程序问题,那么这就是违反了里氏替换原则。
3:开闭原则(Open-Closed Principle)
概念描述:软件实体应当对外扩展开放,对修改封闭,即在不修改原有代码的基础上进行扩展。
如图1的例子,我们使用了kafka中间件来进行消息的发送,如果由于中间件的更换,现在需要替换成RocketMQ,那么就必须要修改原来的代码,这就违反了开闭原则。对此我们应该抽出一个通用的父类,包含发送信息的功能,当需要添加一种消息中间件时,只需要添加一个子类即可,不需要修改原来的代码。
4:依赖倒置原则(Dependency Inversion Principle)
概念描述:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
继续图1的例子,当使用kafka发送消息的时候,我们应该依赖一个抽象接口来发送消息,具体发送方应该是该抽象接口的子类,这样子类如何变更不会影响我调用发送消息方法。
5:接口隔离原则(Interface Segregation Principle,ISP)
概念描述:客户端不应该依赖它不需要的接口。即一个类对另一个类的依赖应该建立在最小的接口上,尽量不要依赖过多的接口。
举例:一个父接口,内部包含吃饭,飞行,打游戏三个方法,对于子类人实现这个接口,飞行这个功能对于人来说是多余的,对于子类鹰实现这个接口,那么打游戏这个方法是多余的,这就违背了接口隔离原则。接口隔离原则申请依赖应该建立在最小的接口上,这里可以对接口进行拆分,根据自己的需要来实现接口。
6:迪米特原则(Law of Demeter,LoD)
概念描述:一个对象应该对其他对象有尽可能少的了解。即一个类应该对其他类知道的越少越好,只与需要交互的类进行通信,减少类与类之间的耦合。
举例:顾客在买电影票的时候,只需要知道售票窗口可以买票即可,而无需知道票据是如何打印的。
联系到实际开发中,一个类无需对外提供的功能/属性就使用private私有化,外部无法即可。