你们的 save 方法是写在实体上,还是写 DAO 上?

导读:本篇文章讲解 你们的 save 方法是写在实体上,还是写 DAO 上?,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

640?wx_fmt=jpeg

注:Dao 在不同语言中的叫法可能不一样。Dao 可以理解为对数据进行持久化的具体实现。

关于实体的保存,笔者知道行业内有两种方式:

  1. dogDao.save(dog);

  2. dog.save();

相信不少同学,现实中,通常使用第一种,很少见到第二种写法。

为了让大家站在同一个讨论上下文,笔者决定贴出更详细的代码。

注:以下代码会省略很多本文不相关的代码,比如数据校验。读者朋友不必太纠结。

第一种写法:save 方法写在 Dao 上


  1. Dog dog = new Dog()

  2. dog.setName('didi');

  3. dog.setColor('white');

  4. dogDao.save(dog);

第二种写法:save 方法写在实体上


  1. // DogService.java

  2. Dog dog = new Dog()

  3. dog.setName('didi');

  4. dog.setColor('white');

  5. dog.save();

这两种写法,有什么区别吗?事实上,从字面上看,没有什么区别。因为 Dog 类的 save() 方法是这样实现:


  1. // Dog.java

  2. public void save(){

  3. dogDao.save(this);

  4. }

但是从抽象的角度来看,就不一样了。

假如你的项目中存在这样的抽象:

640?wx_fmt=png

如果采用第一种写法,意味着,每多出多一种 Animal,我们就必须多写一套 Service。Service 中会很多这样的方法:


  1. // DogService.java

  2. void save(Dog dog){

  3. dogDao.save(dog);

  4. }

  5. // FishService.java

  6. void save(Fish fish){

  7. fishDao.save(fish);

  8. }

  9. // BirdService.java

  10. void save(Bird bird){

  11. birdDao.save(bird);

  12. }

相信大家对于以上代码并不陌生。

但是如果采用第二种方法就不一样了,不论 Animal 新增多少种子类,只需要一个 Service,并只需要一个方法:


  1. // AnimalService.java

  2. void saveAnimal(Animal animal){

  3. animal.save();

  4. }

相对第一种方法,第二种方法更内聚,更简洁。

如何更优雅将前端传过来的数据结构转成抽象类?

采用第一种方法,我们还必须在 Controller 上,类似于 Service 也要针对不同的子类写不同的方法。所以,会出现 N 个接口:


  1. // AnnimalController.java

  2. @PostMapping("/dog")

  3. public String saveDog(@RequestBody Dog dog){

  4. dogService.save(dog);

  5. }

  6. @PostMapping("/fish")

  7. public String saveFish(@RequestBody Fish fish){

  8. fishService.save(fish);

  9. }

  10. @PostMapping("/bird")

  11. public String saveBird(@RequestBody Bird bird){

  12. birdService.save(bird);

  13. }

这不是我们想要的。我们更希望类似这样的:


  1. // AnnimalController.java

  2. @PostMapping("/animal")

  3. public String saveDog(@RequestBody Animal animal){

  4. animal.save();

  5. }

也就是说,每次 Animal 新增子类,我都不用动 Controller 。但是 Controller 并不会自动将前端传入的 JSON 结构转换成 Animal 抽象类。

这个问题的关键点在于序列化过程,我们是否可以定制。换句个说法,就是定制 JSON 结构转成对象的过程,我们就可以将前端的 JSON 数据转成子类,再赋值给 Animal 抽象类了。

笔者使用的是 Spring Boot 的默认 JSON 序列化库,定制某个类的反序列化,只需要在该类上使用注解就可以,代码样例如下:


  1. @JsonDeserialize(using = AnimalDeSerializer.class)

  2. public abstract class Animal{

  3. }

而 AnimalDeSerializer 的实现如下:


  1. public static class AnimalDeSerializer extends StdDeserializer<Animal> {

  2. @Override

  3. public Animal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

  4. TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);

  5. TreeNode animalTypeNode = treeNode.get("animalType");

  6. if(animalTypeNode == null){

  7. return Animal.emptyImplement();

  8. }

  9. String animalType = ((TextNode) animalTypeNode).asText();

  10. switch (animalType){

  11. case "dog": return JSON.parseObject(treeNode.toString(), Dog.class);

  12. case "fish": return JSON.parseObject(treeNode.toString(), Fish.class);

  13. ....

  14. }

  15. }

  16. }

前提是JSON数据中必须有能区分不同子类的字段,这样才可以使用。例如示例中,我们使用 animalType 来进行区分。

嗅觉灵敏的同学会觉得这个 switch 味道不好。但是如何重构呢?笔者常说:要学会使用枚举消除 switch。点到为止。懂的同学就就懂了。不懂的,就算是留给大家的思考题。

后记

现实中并不一定要完全按第一种写法或第二种写法,还要视具体情况而定。本文的主要目的是想让更多人知道,save 方法放哪里这个问题,还有另一种答案。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/71023.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!