一、DDD 中上下文映射常见模式介绍

1.1 什么是 DDD 上下文映射

在软件开发里,DDD(领域驱动设计)是个很实用的方法。当项目规模变大,不同的业务模块就像一个个独立的小世界,这些小世界就是一个个限界上下文。上下文映射就是处理这些限界上下文之间关系的方法。

1.2 常见模式

1.2.1 共享内核

共享内核就是多个限界上下文共享一部分核心的业务逻辑和数据模型。就好比几个部门共同使用一份重要的文件,大家都围绕这份文件开展工作。

示例(C# 技术栈):

// 定义一个共享的用户类,多个上下文都会用到
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

// 在上下文 A 中使用用户类
public class ContextA
{
    public void ProcessUser(User user)
    {
        // 处理用户逻辑
        Console.WriteLine($"Context A is processing user: {user.Name}");
    }
}

// 在上下文 B 中使用用户类
public class ContextB
{
    public void NotifyUser(User user)
    {
        // 通知用户逻辑
        Console.WriteLine($"Context B is notifying user: {user.Name}");
    }
}

注释:这里定义了一个 User 类作为共享内核,ContextAContextB 两个上下文都可以使用这个类来处理相关业务逻辑。

1.2.2 防腐层

防腐层就像是一堵墙,把一个限界上下文和外部的上下文隔离开。它负责把外部上下文的数据和接口转换成本地上下文能理解的形式。

示例(C# 技术栈):

// 外部系统的用户类
public class ExternalUser
{
    public int UserId { get; set; }
    public string FullName { get; set; }
    public string EmailAddress { get; set; }
}

// 本地上下文的用户类
public class LocalUser
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

// 防腐层
public class AntiCorruptionLayer
{
    public LocalUser ConvertExternalUser(ExternalUser externalUser)
    {
        return new LocalUser
        {
            Id = externalUser.UserId,
            Name = externalUser.FullName,
            Email = externalUser.EmailAddress
        };
    }
}

注释:这里定义了外部系统的 ExternalUser 类和本地上下文的 LocalUser 类,防腐层 AntiCorruptionLayer 负责把外部用户转换成本地用户。

1.2.3 客户 - 供应商

一个上下文作为客户,依赖另一个作为供应商的上下文。客户上下文向供应商上下文请求数据或服务。

示例(C# 技术栈):

// 供应商上下文的服务
public class SupplierService
{
    public string GetData()
    {
        return "Data from supplier";
    }
}

// 客户上下文
public class ClientContext
{
    private SupplierService supplierService;

    public ClientContext(SupplierService service)
    {
        this.supplierService = service;
    }

    public void UseSupplierData()
    {
        string data = supplierService.GetData();
        Console.WriteLine($"Client is using data: {data}");
    }
}

注释:SupplierService 是供应商上下文的服务,ClientContext 是客户上下文,它依赖 SupplierService 来获取数据。

1.2.4 伙伴关系

两个上下文之间是平等的合作关系,共同协商和改进。

示例(C# 技术栈):

// 上下文 A
public class ContextA
{
    public void CollaborateWithB(ContextB contextB)
    {
        // 与上下文 B 协作
        contextB.DoSomething();
        Console.WriteLine("Context A is collaborating with Context B");
    }
}

// 上下文 B
public class ContextB
{
    public void DoSomething()
    {
        Console.WriteLine("Context B is doing something");
    }
}

注释:ContextAContextB 相互协作,ContextA 调用 ContextB 的方法来完成协作任务。

1.2.5 遵奉者

一个上下文完全遵循另一个上下文的规则和接口。

示例(C# 技术栈):

// 主上下文的接口
public interface IMainContext
{
    void Execute();
}

// 遵奉者上下文
public class FollowerContext : IMainContext
{
    public void Execute()
    {
        Console.WriteLine("Follower context is executing according to main context");
    }
}

注释:FollowerContext 实现了 IMainContext 接口,遵循主上下文的规则。

二、共享内核的应用场景分析

2.1 应用场景

共享内核适用于多个限界上下文有共同的核心业务逻辑和数据模型的情况。比如一个电商系统,订单上下文和库存上下文都需要用到商品信息,那么商品信息就可以作为共享内核。

2.2 技术优缺点

2.2.1 优点

  • 减少重复开发:多个上下文共享核心部分,避免了重复编写相同的代码。
  • 数据一致性:保证了多个上下文使用的核心数据是一致的。

2.2.2 缺点

  • 耦合度高:多个上下文依赖同一个共享内核,一旦共享内核发生变化,可能会影响多个上下文。
  • 维护困难:共享内核的修改需要谨慎,因为可能会带来意想不到的问题。

2.3 注意事项

  • 严格控制共享内核的范围,只共享必要的部分。
  • 建立良好的沟通机制,确保对共享内核的修改能及时通知到相关上下文。

三、防腐层的应用场景分析

3.1 应用场景

当一个限界上下文需要与外部系统或其他上下文进行交互,而外部系统的接口和数据格式与本地上下文不兼容时,就需要使用防腐层。比如一个企业内部系统需要与第三方支付系统集成,就可以使用防腐层来转换数据和接口。

3.2 技术优缺点

3.2.1 优点

  • 隔离性好:可以把本地上下文和外部上下文隔离开,降低耦合度。
  • 灵活性高:可以根据本地上下文的需求对外部数据进行转换和处理。

3.2.2 缺点

  • 增加开发成本:需要额外开发防腐层的代码。
  • 性能开销:数据转换和处理会带来一定的性能开销。

3.3 注意事项

  • 防腐层的设计要考虑性能和可维护性。
  • 对外部系统的变化要有一定的适应性,避免频繁修改防腐层。

四、共享内核与防腐层的应用场景对比

4.1 从耦合度角度对比

共享内核会使多个上下文之间的耦合度较高,因为它们都依赖同一个核心部分。而防腐层可以降低上下文之间的耦合度,通过隔离和转换来实现与外部上下文的交互。

4.2 从数据一致性角度对比

共享内核可以保证核心数据的一致性,因为多个上下文使用的是同一套数据模型。而防腐层主要关注数据的转换和适配,不一定能保证数据的绝对一致性。

4.3 从开发成本角度对比

共享内核可以减少重复开发,降低开发成本。但防腐层需要额外开发转换逻辑,增加了开发成本。

4.4 从维护难度角度对比

共享内核的维护难度较大,因为一个小的修改可能会影响多个上下文。而防腐层的维护相对独立,只需要关注数据转换和接口适配的部分。

五、文章总结

DDD 中的上下文映射是处理限界上下文之间关系的重要方法,常见的模式有共享内核、防腐层、客户 - 供应商、伙伴关系和遵奉者等。共享内核适用于多个上下文有共同核心的情况,能减少重复开发和保证数据一致性,但耦合度高、维护困难。防腐层适用于与外部系统交互时的接口和数据转换,能降低耦合度、提高灵活性,但增加开发成本和性能开销。在实际开发中,需要根据具体的业务场景和需求来选择合适的上下文映射模式,合理使用共享内核和防腐层,以提高系统的可维护性和扩展性。