限界上下文:从多个方面细讲

发布时间:2023-05-20

一、什么是限界上下文

限界上下文即是在软件开发过程中划分出的一个边界,用以确定各种角色的职责和权限范围等。它定义了系统中各个子系统、模块或对象之间的关系及其可访问的数据量和范围,减少了模块之间的交互,使代码更加可维护和可重用。 限界上下文常见的应用场景是DDD(领域驱动设计)中,在实现DDD中的聚合和实体时,我们需要为每个聚合和实体定义明确的限界上下文。 下面是一个使用DDD实现的购物车系统代码示例:

class ShoppingCart {
    constructor() {
        this.cartItems = [];
    }
    addItem(item, user) {
        if(user.isVip) {//限制只有VIP才能购买该商品
            if(item.stock > 0) {//限制库存不足
                let existItem = findItemInCart(item.id);
                if(existItem) {
                    existItem.amount ++;
                } else {
                    this.cartItems.push({
                        id: item.id,
                        name: item.name,
                        amount: 1,
                        price: item.price
                    })
                }
            }
        }
    }
    findItemInCart(id) {
        return this.cartItems.find(item => item.id === id);
    }
    getCartTotalPrice() {
        return this.cartItems.reduce((total, item) => {
            return total + item.price * item.amount;
        }, 0)
    }
}
class User {
    constructor(name, isVip) {
        this.name = name;
        this.isVip = isVip;
    }
}
class Item {
    constructor(id, name, price, stock) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.stock = stock;
    }
}
const cart = new ShoppingCart();
const user = new User('张三', true);
const item = new Item('001', '电视机', 2399, 20);
cart.addItem(item, user);

二、限界上下文的作用

限界上下文的作用在于划分系统中各个子系统、模块或对象之间的关系及其可访问的数据量和范围,从而减少了模块之间的交互,使代码更加可维护和可重用。 具体的,它能够:

  1. 定义某个对象的作用范围,以及在该范围内对数据修改和读取的限制,减少代码中错误的发生,提升代码的健壮性。
  2. 对于某些对象的访问需要授权的情况,限定访问特定的限界上下文,从而提供了更加严格和精确的安全控制手段。
  3. 能够清晰地描述业务问题,并支持业务和技术分离,减少代码之间的依赖关系。

三、限界上下文的实现

在实现限界上下文时,我们需要考虑以下几点:

  1. 确定限界上下文的范围,必须清楚地知道每个对象所属性的上下文,避免对象的依赖混乱。
  2. 实现限界上下文必须符合领域驱动设计(DDD)的原则,即围绕业务领域建模,而不是围绕技术框架建模。
  3. 限界上下文的划分必须有明确的目的,且必须与具体业务需求相符。 下面展示一个使用限界上下文来实现的数据访问对象:
class UserDAO {
    constructor(client, ctx) {
        this.client = client;
        this.tableName = ctx + '_users';
    }
    getById(id) {
        return this.client.query(`SELECT * FROM ${this.tableName} WHERE id=${id}`);
    }
    create(user) {
        return this.client.query(`INSERT INTO ${this.tableName} VALUES ${user}`);
    }
}
const mysqlClient = new MysqlClient();
const userDao = new UserDAO(mysqlClient, 'blog'); //限制只能操作blog上下文的User对象
userDao.create({id:1, name:'张三', age: 18}); //MysqlClient写法可以参考Mysql官方文档

四、限界上下文的注意事项

在实际的开发中,我们需要注意以下几个方面:

  1. 限界上下文的划分应该尽量避免出现交叉依赖关系,否则将会导致限界上下文间的耦合性较高,使得系统的可维护性和可扩展性下降。
  2. 限界上下文的名称应该清晰、简洁,并且避免出现歧义,以避免在设计中出现与需求不符的问题。
  3. 在定义限界上下文时,必须避免过度约束对象的行为,防止出现对象行为不足或者行为过度的情况。 综上,限界上下文可以为我们构建性能高、可维护性强的应用程序提供指南,并提供了设计领域对象的一种规范化的方法。在使用的过程中,我们需要结合 DDD 的原则,将限界上下文分配给正确的领域对象。只有合理地使用限界上下文,才能构建更加健壮和高效的系统。