有多少程序员思考过自己是否在面向对象编程?
有过一定工作经历的java程序员,在平常写代码时,会使用面向对象来进行编程吗?虽然java是面向对象的编程语言,但是大部分程序员还是平铺直叙的面向过程方式来开发。那么我们平常说面向对象到底在说什么?
什么是面向对象编程?
它是以类和对象作为组成代码的基本单元,结合了封装,继承,抽象,多态的特性。
传统的MVC是否符合面向对象编程?
// ------ controller&vo -------
public class UserController {
private UserService userService;
public UserVo getUserById(Long userId) {
UserBo userBo = userService.getUserById(userId);
UserVo userVo = [...convert userBo to userVo...];
return userVo;
}
}
public class UserVo {
private Long id;
private String name;
private String cellphone;
... setget 方法省略 ...
}
// ----------SERVICE&BO-------------
public class UserService {
private UserDao userDao;
public UserBo getUserById(Long userId) {
// 1 参数校验
// 2 查询数据库
// 3 封装返回结果
UserEntity userEntity = userDao.getUserById(userId);
UserBo userBo = [...convert userEntity to userBo...];
return userBo;
}
}
public class UserBo {
private Long id;
private String name;
private String cellphone;
... setget 方法省略 ...
}
//------------- Dao&entity ------------
public class UserDao {
public UserEntity getUserById(Long userId) { //... }
}
public class UserEntity {
private Long id;
private String name;
private String cellphone;
... setget 方法省略 ...
}
上面代码是纯纯的面向过程编程的代码
- 不满足封装的特性 封装定义: 类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。这句话怎么理解呢?我们通过一个简单的例子来解释一下。
UserBo,UserEntity,UserVo 只有属性,和简单的setget 方法,并没有行为。
- 仅仅封装了属性,并没有封装对象的行为。
- 暴露出public的setget方法,和直接定义 public 属性无异。应该仅仅暴露有必要的setget
-
不符合单一职责 是违背了SRP(Single Responsbility Principle)单一职责原则。这段代码里混杂了业务计算、校验逻辑、基础设施等,在未来无论哪 一部分的逻辑变更都会直接影响到这段代码。
-
不符合依赖倒置原则(DIP) 依赖倒置:高层模块不要依赖低层模块。高层模块和低层模块应该通过抽象来互相依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象。
上面代码:service 直接依赖 dao UserEntity userEntity = userDao.getUserById(userId);
- dao查询返回的userEntity侵入到了service层
- service没有依赖抽象的repo层,而是依赖了dao(dao是mysql的一个代表,后续切换其他数据源时,service层代码还得调整。)
public class UserService {
private UserRepository userRepository;
public UserBo getUserById(Long userId) {
UserBo userBo = userRepository.queryUser(userId);
return userBo;
}
}
//-----repo抽象------
public class UserRepository {
private UserDao UserDao;
public UserBo queryUser(Long userId) {
UserEntity userEntity = userDao.getUserById(userId);
UserBo userBo = [...convert userEntity to userBo...];
}
}
// ------dao层具体实现--------
public class UserDao {
public UserEntity getUserById(Long userId) { //... }
}
- 通过上面代码调整,service不再依赖具体的dao层,而是依赖抽象的repo层,同时service 不再依赖下游返回的entity对象。只操作service层的userBo对象。
总结: 虽然代码很简单,大家也都是这样写的,但是我们也要多思考如何写好代码,如何把面向对象的理论和实践结合起来使用。
首次更文,有很多写的不好的地方。大家也可以针对上面代码提出自己的见解。还有哪些不符合面向对象编程的地方,一起讨论,一起成长。