学习领域模型-上下文过载


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



富知识类 User


我们有三个功能模块, 落地在领域建模时, 分为三个上下文.
在这里插入图片描述

接着对它们的交集点 User 建模, 得到的代码如下:

public class User {
    private long id;
    
    // 社交上下文
    private List<Friendship> friends;
    private List<Moments> moments;
    
    // 订阅上下文
    private List<Subscription> subscriptions;
    
    // 订单上下文
    private List<Order> orders;
    private List<Payment> payments;
    
    // 社交上下文
    public void make(Friendship friend) {
      ...
    }
    
    public void break(Friendship friend) {
      ...
    }
    
    // 订单上下文
    public void placeOrder(Column column) {
      ...
    }    
    
    // 订阅上下文
    public boolean canView(Content content) {
      ...
    }        
}

它的问题是, 一个类中包含太多信息, 让维护者难以理解.



角色对象 (Role Object)


在不同的上下文中, User 用户以不同的角色与其他对象发生交互.

在这里插入图片描述

角色对象作为实际类, 来承载各自上下文, 具体代码如下:

public class Reader {
    private User user;
    private List<Subscription> subscriptions;
    
    public Reader(User user) {
        ...
    }
    
    // 订阅上下文
    public boolean canView(Content content) {
      ...
    }        
}


public class Buyer {
    private User user;
    
    private List<Order> orders;
    private List<Payment> payments;
    
    public Buyer(User user) {
        ...
    }
    
    // 订单上下文
    public void placeOrder(Column column) {
      ...
    }    
}


public class Contact {
    private User user;
    
    private List<Friendship> friends;
    private List<Moments> moments;
    
    public Contact(User user) {
        ...
    }
    
    // 社交上下文
    public void make(Friendship friend) {
      ...
    }
    
    public void break(Friendship friend) {
      ...
    }

Repository 对象中, 做具体的角色转换.

public interface UserRepository {
    User findById(long id); 
    
    Buyer asBuyer(User user); 
    
    Reader asReader(User user);
    
    Contact asContact(User user);
}


public class UserRepositoryDB implements UserRepository {
    public User findById(long id) {
        return db.executeQuery(...)
    }
    
    public Buyer asBuyer(User user) {
        return new Buyer(user, db.executeQuery(...));
    }
    
    public Reader asReader(User user) {
        return new Reader(user, db.executeQuery(...));
    }
    
    public Contact asContact(User user) {
        return new Contact(user, db.executeQuery(...));
    }
}

实际调用的代码就变成:

User user = repository.findById(....);

Buyer buyer = repository.asBuyer(user);
Reader reader = repository.asReader(user);
Contact Contact = repository.asContact(user);



上下文对象 (Context Object)


使用角色对象的模式, 虽然做到了将 User 与各个上下文信息解耦, 但还是存在一个问题.

在 UserRepositoryDB 中我们对角色对象的转换, 是依据数据库查询的方式, 找到其角色对应的上下文信息.

也就是说, User 用户的仓储实现, 与角色对象的上下文实例化没有解耦, 如果角色对象的上下文信息来自 RestFul API 亦或是其他途径, 没有办法灵活变通.


解决这类问题的通用手段就是中间层… 亦如角色对象一样, 我们创建出上下文对象, 用来解耦上下文信息.

interface SubscriptionContext {
    interface Reader {
        boolean canView(Content content);    
    }
    
    Reader asReader(User user);
}


interface SocialContext {
    interface Contact {
        void make(Friendship friend);
        void break(Friendship friend);
    }
    
    Contact asContact(User user);
}


interface OrderContext {
    interface Buyer {
        void placeOrder(Column column);        
    }
    
    Buyer asBuyer(User user);

此时, UserRepository 的关联信息就不再是角色对象, 而是上下文对象, 借由上下文对象的具体实现, 实例化角色对象.

interface UserRepository {
    User findUserById(long id);
    
    SubscriptionContext inSubscriptionContext();
    SocialContext inSocialContext();
    OrderContext inOrderContext();
}


public class UserRepositoryDB {
    //通过依赖注入获取不同的上下文对象
    @Inject private SubscriptionContext subscriptionContext;     
    
    @Inject private SocialContext socialContext;
    
    @Inject private OrderContext orderContext;
    
    ...
}

最后, 使用方式变为:

UserRepository users = ....;
User user = users.findUserById(...);

Buyer buyer = users.inOrderContext().asBuyer(user);
Reader reader = users.inSubscriptionContext().asReader(user);
Contact contact = users.inSocialContext().asContact(user);

另外, 上下文对象还有个好处, 当我们需要跨上下文协作, 各种其他上下文的依赖可以直接放在上下文对象中, 那么实际的业务代码就能获取到这些上下文对象信息, 参与逻辑.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值