如何写工程代码——重新认识面向对象

作者结合自身经历,以登录模块为例,指出常规CURD编程方式存在复用难、维护成本高、事务处理难等弊端,原因是缺乏面向对象思维。重新解释了面向对象中对象的概念,强调对象应包含数据和行为,这样做能使责任分明、统一业务表达,还利于理解设计模式。

工作一年,维护工程项目的同时一直写CURD,最近学习DDD,结合之前自己写的开源项目,深思我们这种CURD的编程方式的弊端,和朋友讨论后,发现我们从来没有面向对象开发,所以写这篇文章,希望更多人去思考面向对象,不只是停留在背书上

下面以开发一个常规的登录模块为例,模拟实现一个登录功能,一步步地去说明其中的弊端和重新解释面向对象

常规的开发方式

创建模型

@Data
@NoArgsConstructor
class User{
    private Integer Id;
    private String name;
    private String password;//加密过的密码
  private Integer status;//账号状态
}

class UserRepository{
  User getByName(String name);
}

我们都知道mvc,所以会这么写

class UserController{
    @RequestMapping("/login")
    public void login(String name,String password){
        userService.login(name,password);
    }
}

class UserService{
    public void login(String name,String password);
}

class UserServiceImpl implements UserService{
    public void login(String name,String password){
        //1.查出这个用户
        User user = userRepo.getByName(name);
    //2.检查状态
    if(user.getStatus()!=1){
      //登录失败
    }
    //3.检查密码
    if(!Objects.equals(md5(password),user.getPassword())){
        //登录失败
    }
    //登录后续
    }
}

虽然这个login方法有点丑,这还是没有打点,日志,生成登录态的情况下。我们所有的业务都写在了UserService里面,可能很多人不觉得这样写有什么问题。如果代码写多一点的程序员,可能会把每一步都抽成一个方法

public void login(String name,String password){
  //1.查出这个用户
  User user = userRepo.getByName(name);
  //2.检查状态
  checkUserStatus();
  //3.检查密码
  checkPassword();
  //登录后续
}

这样看是好看很多,但是换汤不换药,维护过工程项目的同学都会发现,项目里基本都是这种代码,维护起来成本极高:

  1. login方法被抽成几个方法,login方法是简单了,service却臃肿了

  2. service臃肿后开始拆分service,再不济开始建立多一层manage之类的

  3. 复用极其困难,因为checkUserStatus这种方法往往是私有,并且这种抽离对其它业务场景是否合适也不好说

  4. 在代码开始出现冗余时,会开始写一些带有业务逻辑的Utils,把污染扩散到Utils

  5. 由于复用极其困难,开始出现多个类似功能的方法,分布在不同类里,后继维护项目的人很难分清类似方法的区别

  6. 因为不好统一表达语义,DTO等对象会在service层泛滥,controller和service耦合严重,导致分层变得没有意义

  7. 1,2其实是一个死循环,最后直接反映到项目难以维护上

  8. 在多数据源,多事务的情况下,难以确定事务边界,容易出现事务不能回滚的情况

  9. 单元测试的编写是个噩梦,尝试写单测的同学应该深有体会

为什么会这样呢?因为我们到这里为止,依然还是面向过程编程,完全没有面向对象的思维。代码其实都是堆起来,责任和边界不清晰,导致复用很难,维护变更的成本很高,所以项目经过多人维护后会变得更严重。唯一像面向对象的代码就是User user = userRepo.getByName(name)这一句了

重新认识面向对象

为什么说这一句有面向对象的意味?因为这行含义十分明显,谁做了什么,我觉得这是一个很好的判断原则,在scala里面,是可以把a.do(thing)写成a do thing主语确定了责任,边界。在这里,用户repo获取(生成)一个用户对象。虽然我们一直在说OO,什么封装继承多态,六大原则,张口就来,但是一写起代码就变成过程式开发。很多人说设计模式很难学,用不上,很大原因是连对象是什么都没概念,还怎么谈面向对象设计

有人会问,上面的User不是对象吗?这个问题我在学校的时候也被别人问过,当时也觉得很疑惑。当时的问题是这样的,你觉得上面的User和下面这个有区别吗

struct User
{
   int id;
   char name[50];
   char password[50];
   int status;
} user;

是的,这是c语言的结构体。你当然不会说这个是对象。这里有个误区,我们平时说的Java对象,其实指的是面向对象语言Java里类的实例,并不等同于面向对象里的对象。所以上面java对象也不见得是真的OO对象

可以看一下维基百科关于对象的说法

对象是什么

OO的对象应该是data+behavior,所以我们上面的User对象没有行为,只是一个数据结构。试想一下,我是用户,校验密码应该是我自己的事,我用什么加密应该也是我来决定,甚至我加不加密也是我说了算。同样的,我的状态应该也是我来管理,我们的User可以改造成这样

@Data
@NoArgsConstructor
class User{
    private Integer Id;
    private String name;
    private String password;//加密过的密码
  private Integer status;//账号状态
  
  public boolean checkPassword(String pass){
    return Objects.equals(md5(pass),this.password);
  }
  
  public boolean isNormal(){
    return this.status==1
  }
  
  //这里啰嗦一下,有时候我们不太好把行为写到数据库模型类,可以单独建立一个User类,这个User类也就是DDD里面的领域对象。如果持久层使用JPA,JPA的数据模型类即是领域对象,JPA允许通过注解去把领域对象绑定到数据模型上。
}

这样,Service的代码就简单很多,只需要关注登录的逻辑,不需要关心细节

public void login(String name,String password){
  //1.查出这个用户
  User user = userRepo.getByName(name);
  //2.检查状态
  if(!user.isNormal()){
  
  }
  //3.检查密码
  if(!user.checkPassword(password)){
  
  }
  //登录后续
}

这样做有什么好处呢

把固有的逻辑由对象本身负责,责任分明,边界清晰,业务逻辑统一集中,编写单测更容易

更重要的是,我们的User对象建立起来,有关用户相关的逻辑,方法,我们可以通过User来表达,并且可以在各个分层中传递,统一业务表达语言,可以有效遏制DTO在Service层泛滥的问题。后续会说明一下DTO的问题

理解了对象是什么后,会更好地反思封装的重要性,进而深入理解六大原则的含义,开始抽象出接口,在实践接口的基础上慢慢地会形成一些手法和技巧,那便是设计模式。而这一切都需要在开发时保持思考,这样写是否流程清晰,边界分明,复用是否容易,最重要的是,是否符合业务的表达,而不是写出service类do anything的过程式代码

转载于:https://www.cnblogs.com/scau-chm/p/10800885.html

乐播投屏是一款简单好用、功能强的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值