电商项目整洁架构下,如何避免重复模型并遵循DRY原则与依赖规则?
四层整洁架构+CQRS下模型重复问题的解决方案
一、代码生成工具自动生成模型与映射
- 基于T4模板、Roslyn或代码生成框架,定义包含共用属性和各层特有属性的模板,一键生成领域Entity、应用层命令/查询、UI层VM文件,以及对应的映射配置。
- 示例:针对
Option系列模型,在模板中配置Name、Value等共用属性,再分别为领域层添加Id、CreatedAt,UI层添加IsSelected,应用层添加OperationType,执行模板即可生成所有重复代码。
二、用共享契约接口减少重复定义
- 在独立的契约项目中定义包含共用属性的接口(符合整洁架构“所有层依赖抽象”的规则),各层模型实现该接口并仅补充自身特有属性。
- 代码示例:
// 契约层接口 public interface IOptionCore { string Name { get; set; } string Value { get; set; } int SortOrder { get; set; } } // 领域层实体 public class OptionDetail : IOptionCore, IEntity { public Guid Id { get; set; } public DateTime CreatedAt { get; set; } // 实现接口共用属性 public string Name { get; set; } public string Value { get; set; } public int SortOrder { get; set; } } // UI层视图模型 public class OptionVM : IOptionCore { public bool IsSelected { get; set; } // 实现接口共用属性 public string Name { get; set; } public string Value { get; set; } public int SortOrder { get; set; } } - 映射工具(如AutoMapper)可基于接口自动匹配属性,无需手动编写大量映射规则。
三、优化CQRS模型结构,复用基础模型
- 对业务逻辑相似的命令/查询,定义基础父类,具体命令/查询继承父类以复用属性。
- 代码示例:
// 应用层基础命令 public abstract class OptionCommandBase { public string Name { get; set; } public string Value { get; set; } public int SortOrder { get; set; } } public class CreateOptionCommand : OptionCommandBase, IRequest<Guid> { // 无额外属性,直接继承 } public class UpdateOptionCommand : OptionCommandBase, IRequest<bool> { public Guid Id { get; set; } }
四、利用映射工具的自动映射能力
- 配置AutoMapper/Mapster等工具的全局映射规则,基于约定自动匹配同名属性。对于实现同一契约接口的模型,可直接配置接口间的映射,所有实现类自动继承该规则。
- 代码示例(AutoMapper):
public class MappingProfile : Profile { public MappingProfile() { CreateMap<IOptionCore, IOptionCore>(); // 接口间基础映射 CreateMap<OptionDetail, AppOption>().ReverseMap(); CreateMap<AppOption, OptionVM>().ReverseMap(); } }
五、谨慎放宽架构边界,复用基础DTO
- 对于无业务逻辑的纯数据载体模型,可将其放在抽象契约层,允许各层直接使用,仅在需要扩展时创建子类。比如定义
OptionBase在契约层,领域层OptionDetail继承并添加领域属性,UI层OptionVM继承并添加UI属性。 - 注意:必须保证这些基础模型无状态、无业务逻辑,避免破坏架构的独立性和可测试性。
内容的提问来源于stack exchange,提问作者sarang lad
相关产品推荐
相关产品推荐

