文章来源:
http://www.superwu.cn/2013/08/15/463/
java分层开发、分层调用已经是业界的共识。通常有一套这样的理论在指导着我们:
1.系统应该划分层次,最经典的莫过于MVC分层,很多框架也是基于此开发的。我们通常把系统划分为视图层、控制层、业务逻辑层、数据访问层、数据存储层。
2.层次划分清楚,上层代码只能调用下层代码,下层代码不能调用上层代码。比如控制层代码可以调用业务逻辑层,业务逻辑层可以调用数据访问层等。
3.每层开发应该使用接口,对外公布接口。当有上层调用的时候,可以修改本层实现,而不必修改调用方的代码。
按照这个指导思想开发,可能会出现以下层次结构划分:
-视图层
-控制层
-业务逻辑层接口
-业务逻辑层实现
-数据访问层接口
-数据访问层实现
-数据存储层
那么,可能出现以下的代码调用现象
//控制层代码 public class UserAction{ public UserService userService; public String listAll(){ List<User> allUsers = userService.findAll(); //省略其余代码 } } //业务逻辑层接口 public interface UserService{ public <User> findAll(); } //业务逻辑层实现 public class UserServiceImpl implements UserService{ private UserDao userDao; public List<User> findAll(){ return userDao.findAll(); } public void setUserDao(UserDao userDao){ this.userDao = userDao; } } //数据访问层接口 public interface UserDao{ public <User> findAll(); } //数据访问层实现 public class UserDaoImpl implements UserDao{ public <User> findAll(){ //省略JDBC调用逻辑 } }
对于一个系统开发的大部分java后端代码而言,也是遵循二八律的,百分之八十是简单的增删改查操作,真正的复杂业务逻辑占百分之二十。代码越多,意味着bug可能越多。并且,对于大部分系统,只有一种接口实现。业务逻辑层调用数据访问层也是简单的一行代码。那么,上面的实现是否有些臃肿?
按照我的观点,确实非常臃肿。带来几个问题:
1.工作量增加,这是毫无疑问的,因为写的代码多了嘛;
2.代码越多,bug可能越多,风险可能越高;
3.维护难度增加。如果数据访问层接口改动了,那么至少要影响数据访问层实现代码、业务逻辑层实现代码的修改;
4.调用层次增加,系统能耗增加,可能会影响系统性能;
另外,在泛型大行其道的java开发中,不利用泛型,真是有些浪费了。基于此,我们可以进行如下改进:
//控制层 public class UserAction{ private UserService userService; public String listAll(){ List<User> userList = userService.findAll(); //省略其他操作 } } //业务逻辑层 public class UserService{ private UserDao userDao; public List<User> findAll(){ return userDao.findAll; } //省略注入代码 } //数据访问层 public class UserDao{ public List<User> findAll(){ //省略JDBC代码 } }
这样改进之后,少了两个层次,代码质量一点没变。这解决了调用层次过多的问题,那么简单调用问题还没有解决。我们可以根据泛型,作进一步的简化
//控制层 public class UserAction{ private UserService userService; public String listAll(){ List<User> userList = userService.findAll(); //省略其他操作 } } //业务逻辑层 public class UserService{ private UserDao userDao; public List<User> findAll(){ return userDao.findAll; } //省略注入代码 } //数据访问层基类 public abstract class BaseDao<T>{ public List<T> findAll(){ //省略JDBC代码 } public T get(){ //省略JDBC代码 } public void save(T t){ //省略JDBC代码 } public delete get(T t){ //省略JDBC代码 } //省略其他操作 } //数据访问层子类 public class UserDao extends BaseDao<User>{ //可以不用写代码,已经继承了BaseDao的方法 }
这次改进是增加了数据访问层的基类BaseDao,增加了很多通用的操作。这样,具体Dao子类就可以仅仅是一个空壳了。UserDao的功能一点也没变,但是需要我们维护的代码量明显减少了。当然,你可以对业务逻辑层抽取出一个父类,控制层抽取出一个父类。
如果系统明显不复杂,甚至业务逻辑层和数据访问层合并成一个,也是可以的。
综上,我们的原则是效率优先,兼顾质量。非常优美的设计,如果不能按期完工,一样是无意义的。当然,这话,也不是全面否认设计的存在。
在我的EasyQuery中,我就权衡了代码质量和系统设计的关系,使用了大量避免代码重复的设计,尽量用少量的代码完成更多的功能。这样,以后维护的时候会更加的简单。