你会面向对象编程吗?

222 阅读3分钟

有多少程序员思考过自己是否在面向对象编程?

有过一定工作经历的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 方法省略 ...
}

上面代码是纯纯的面向过程编程的代码

  1. 不满足封装的特性 封装定义: 类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据。这句话怎么理解呢?我们通过一个简单的例子来解释一下。

UserBo,UserEntity,UserVo 只有属性,和简单的setget 方法,并没有行为。

  • 仅仅封装了属性,并没有封装对象的行为。
  • 暴露出public的setget方法,和直接定义 public 属性无异。应该仅仅暴露有必要的setget
  1. 不符合单一职责 是违背了SRP(Single Responsbility Principle)单一职责原则。这段代码里混杂了业务计算、校验逻辑、基础设施等,在未来无论哪 一部分的逻辑变更都会直接影响到这段代码。

  2. 不符合依赖倒置原则(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对象。

总结: 虽然代码很简单,大家也都是这样写的,但是我们也要多思考如何写好代码,如何把面向对象的理论和实践结合起来使用。

首次更文,有很多写的不好的地方。大家也可以针对上面代码提出自己的见解。还有哪些不符合面向对象编程的地方,一起讨论,一起成长。