学习领域模型-数据库的断舍离

2021/7/18 2:05:47

本文主要是介绍学习领域模型-数据库的断舍离,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

    • Repository 仓储模式
    • 关联对象
    • 总结


(学习极客时间-如何落地业务建模 的笔记, 展示代码皆使用文中例子, 仅做学习记录)



Repository 仓储模式


我们知道, 聚合根实体的实例化是需要借助数据库, 但这种逻辑放在实体内, 会混杂领域模型的含义. 于是 Eric 的一书中, 采用 Repository 仓储模式单独做数据相关工作.

具体方式是定义聚合根实体的 Repository 接口, 以及 DB 实现, 将保存与查询等操作置于其中.

借用文中的例子:

class User {

   private List<Subscription> subscriptions;

   // 获取用户订阅的所有专栏
   public List<Subscription> getSubscriptions() {
     ...
   }
   
   // 计算所订阅的专栏的总价
   public double getTotalSubscriptionFee() {
     ...
   }
}

class UserRepository {
  ...
  public User findById(long id) {
    ...
  }

UserRepository 将 User 的实例化查询数据库隔离, 帮助构建包含有 Subscriptions 订阅专栏集合的 User 用户实例.

这里存在一个问题, 如果订阅专栏集合过大, 那么内存容量就是个问题. 现实场景中一般是用分页限定查询大小的. 那么就会理所当然的在 User 实例中加上一个方法.

public List<Subscription> getSubscriptions(int from, int size);

这样做是否真的能解决内存消耗过大的问题? 毕竟 UserRepository#findById 时就已经将 subscriptions 全部读取了出来 (即便是用懒加载, 其重要逻辑也需要在 Subscription 实体中编写, 超出领域行为范畴).

另一个问题是, User 中的这种行为也是超出它本身的含义, 分页这种数据库行为也需要隔离.

由此引出新的模式, 关联对象.



关联对象


根据用户与订阅的关系, 我们建立一个关联对象 MySubscriptions, 含义为我的订阅.

public interface MySubscriptions extends Iterable<Subscription> {
   List<Subscription> subList(int from, int to); //分页
   double getTotalSubscriptionFee(); //获取总共花费
   int count(); //获取总订阅数
   Iterable<Subscription> sort(...);
   ....
}

那么 User 实体中, 就不直接关联 Subscription 实体了

public UserRepositoryDB implements UserRepository {
  ...
  public User findBy(long id) {
      User user = .....;
      return setMySubscription(user);
  }
  
  public List<User> findBy(....) {
      List<User> user = .....;
      return user.map(user -> setMySubscription(user));
  }
  
  private User setMySubscription(User user) {
      user.setMySubscriptions(new MySubscriptionDB(db, user));
      return user;      
  }
}
public class User {
  private MySubscriptions mySubscriptions;
  
  public MySubscriptions getMySubscriptions() {
     return mySubscriptions
  }
}

当我们借助 UserRepository 实例化 User 的时候, 也不必将相关订阅全部读到内存. 要读到订阅只能通过 MySubscription 接口的分页方法, 有限度的即时读取. 而读取逻辑则归到关联对象上.

package model.impl.db;

public class MySubscriptionsDB implements MySubscriptions {
  ...
  private User user;

  public List<Subscription> subList(int from, int to) {
    return db.executeQuery(...);
  }
  ...



总结


为了保有领域模型的聚合关系, 我们会在聚合根实体中设置关联的实体, 但是当它为一对多关系时, 一次构建实体带来的性能问题就很凸显.

如何做到即保有模型, 又有好的性能, 关联对象是解决它的一种设计模式. 它就像是中间层一样, 解耦这个关联问题.



这篇关于学习领域模型-数据库的断舍离的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程