为什么说二进制依赖一个组件时不准调用它的内部API? 比如说,对bean-biz.jar,应用层只准调用BeanService.getBean(),而不准调用BeanDAO.getBean()?
你会说这是为了“封装性”,以“避免不必要的耦合”。但直接耦合BeanDAO.getBean()和BeanDAO.deleteBean()有什么“具体”的坏处呢?
我的结论是:
1.
如果同时依赖BeanService.getBean()和BeanDAO.getBean(),就意味着对同一个操作形成了“调用上的冗余”; 当一个发生变化时,另一个也要跟着变,而且变得很尴尬。
2.
如果绕过BeanService直接调用BeanDAO.deleteBean(),就意味着依赖了组件的内部实现;而内部实现往往是不稳定的,当内部实现改变时,应用层也要发生改变,一种本可以避免的改变。
代码阐述:
1. 调用的冗余
//改变发生前
public class BeanService {
public Bean getBean(Long id) {
return beanDAO.getBean(id);
}
}
public class WiseAction {
public void showBeanDetail(){
Bean bean = beanService.getBean(id);
}
}
public class RogueAction {
public void showBeanDetail() {
Bean bean = beanDAO.getBean(id);
}
}
//改变:后来出了规定,对Bean的获取必须走缓存
public class BeanService {
public Bean getBean(Long id) {
Bean bean = Cache.get(id);
if (bean == null) {
bean = beanDAO.getBean(id);
}
return bean;
}
}
////只依赖了BeanService的应用层代码无须改变
public class WiseAction {
public void showBeanDetail(){
Bean bean = beanService.getBean(id);
}
}
////依赖了BeanDAO的应用层代码需要改变以加入缓存逻辑;同时,这也导致了缓存逻辑的重复
public class RogueAction {
public void showBeanDetail() {
Bean bean = Cache.get(id);
if (bean == null) {
bean = beanDAO.getBean(id);
}
return bean;
}
}
2. 依赖了不稳定的内部实现
//改变发生前
public class BeanService {
public void deleteBean(Long id) {
beanDAO.deleteBean(id);
}
}
public class WiseAction {
public void removeBean(){
beanService.deleteBean(id);
}
}
public class RogueAction {
public void removeBean() {
beanDAO.deleteBean(id);
}
}
//改变:后来规定对Bean不能物理删除,只允许逻辑删除(把某个标志位设置为false)
public class BeanService {
public void deleteBean(Long id) {
Bean bean = getBean(id);
bean.setValid(false);
beanDAO.updateBean(bean);
}
}
//同时,为了防卫,BeanDAO.deleteBean()方法应该删除
////只依赖了BeanService的应用层代码不用变
public class WiseAction {
public void removeBean(){
beanService.deleteBean(id);
}
}
////依赖了BeanDAO的应用层代码必须改变,因为BeanDAO.deleteBean()已经不存在了
public class RogueAction {
public void removeBean(){
beanService.deleteBean(id); //这时应用层代码也只好改成依赖BeanService,早知今日,何必当初?
}
}