不该用的代码生成器
在十几年前我还在上大学学编程的时候,就已经诞生了各种各样的代码生成器。
现在2023年了,各种代码生成器依然大行其道。
读取数据库表结构并生成相应的Entity、Mapper、Service、Controller。
为什么我标题说不该用呢?
主要的点在于,我认为生成Service和Controller是不该的、错误的。
三大弊端
重复冗余代码
生成Entity和Mapper的过程显然是重复、枯燥的,所以造出个代码生成器显然是没有问题。
Entity的代码本身也不可能是重复的,但是Controller、Service显然是同样的模板生成出来的,
按照我们平时优化代码的习惯,相似的代码不就该将变化的部分提取成变量/方法抽象封装一层吗?
既然都能模板化,为什么不能在运行时用占位符动态计算呢?
举例,一堆的雷同Controller
@RestController
@RequestMapping("/users")
public class UserController {
private UserService userService;
@GetMapping("/")
public List<User> list(){
return userService.list();
}
@GetMapping("/{id}")
public User get(@PathVariable("id") String id){
return userService.findById(id);
}
}
@RestController
@RequestMapping("/roles")
public class RoleController {
private RoleService roleService;
@GetMapping("/")
public List<Role> list(){
return roleService.list();
}
@GetMapping("/{id}")
public Role get(@PathVariable("id") String id){
return roleService.findById(id);
}
}
上面这种重复雷同的代码,为什么不能直接用BaseController的形式,通过通配符+泛型来代替?
@RestController
public class BaseController {
@GetMapping("/{entity}")
public List list(@PathVariable("entity") String entity){
BaseService baseService = findService(entity);
return baseService.list();
}
@GetMapping("/{entity}/{id}")
public Object get(@PathVariable("entity") String entity, @PathVariable("id") String id){
BaseService baseService = findService(entity);
return baseService.findById(id);
}
}
其实Spring就已经有了 Spring Data Rest,根本就不需要用代码生成器造一堆重复的代码出来。
程序是用来解决重复劳动的,不是用来制造重复代码的。
而代码生成器生成的Controller、Service就是这样一堆重复代码。
业务抽象与技术抽象的混淆
Controller是业务的抽象,Entity是技术的抽象,而Service是两者的转换区。
举个例子,用户将雪碧、可乐两件商品加入购物车,点击下单,那么Controller应该有个下单接口。
在数据库设计上,可能你会设计一个订单表Order和订单商品表OrderItem,这是技术的设计。
至于Service,干的就是按订单规则生成订单号、将数据存到Order和OrderItem表,可能还有优惠计算、积分累计、后续的付款单号生成等逻辑。
这是从业务需求到技术设计的一般流程。
而如果你用代码生成器,因为有Order表和OrderItem表所以不管三七二十一就生成了OrderController、OrderItemController、 OrderService、OrderItemService,这难道不是一件很奇怪的事吗?
再比如,你用的就不是MySQL这种关系型数据库,而是MongoDB这种非关系型文档数据库, 你可能就不会建Order和OrderItem两个表,而是直接在Order里加个items字段存数据。
在这种情况下,你绝对只会建一个OrderController、一个OrderService吧?
不会有OrderItemController、OrderItemService了。
这时问题来了,相同的业务需求,你有多少个Controller、多少个Service取决于你建了多少表?
显然你这不是面向业务编程,而是面向数据库编程了。
Service与Dao的界限
很多人分不清Service与Dao的边界,原因也就在于此。太多无用的Controller和Service了。
很多人都写出 aService调用bService再由bService调用bDao 这样的代码。
这里也请移步查看我的另一篇文章aService直接调用bDao合适吗?
如果你觉得本文对你有帮助或不错,可略表心意,请我喝一杯冰可乐。 ☕