代码重构——移除领域模型的属性“set”块

设计领域模型的时候,属性的set块会带来一些问题,例如下面的一个类。

    public class SearcherBase
    {
        public IApplication Application { get; set; }

        public virtual IIndexManager IndexManager { get; set; }

        public virtual async Task<SearchResult> SearchAsync(Query query)
        { //some code }
    }

当客户端调用该类时,看到ApplicationIndexManager两个属性,会不知所措: 该不该给他们赋值呢?这两个玩意是干吗的呢?
事实上,这两个属性的set块,在 SearcherBase类型初始化的时候才会被用到。

    public class SearcherBuilder
    {
        private IocResolver _iocResolver;

        public SearcherBase Build(IApplication app, IIndexManager manager)
        {
            SearcherBase searcher = _iocResolver.Resolve(app.SearcherType) as SearcherBase;
            searcher.Application = app,
            searcher.IndexManager = manager;
            return searcher;
        }
    }

将领域模型的属性set块暴露出来,会造成属性的语义不明,没有表达出业务逻辑(初始化),不符合DDD有关领域模型设计的要求。因此,可以根据情况对SearcherBase做如下两种方式的重构:

  1. 尽可能多的在构造函数中初始化内部成员
    public class SearcherBase
    {
        public SearcherBase(IApplication app, IIndexManager manager)
        {
            Application = app,
            IndexManager = manager;
        }
        public IApplication Application { get; }

        public virtual IIndexManager IndexManager { get; }

        public virtual async Task<SearchResult> SearchAsync(Query query)
        { //some code }

    }
  1. 对于该例,由于关系到通过容器初始化实例,可以创建SearcherBase的初始化方法
    public class SearcherBase
    {
        public void Initialize(IApplication app, IIndexManager manager)
        {
            Application = app;
            IndexManager = manager;
        }
        public IApplication Application { get; private set;}

        public virtual IIndexManager IndexManager { get; set;}

        public virtual async Task<SearchResult> SearchAsync(Query query)
        { //some code }
    }

    public class SearcherBuilder
    {
        private IocResolver _iocResolver;
        public SearcherBase Build(IApplication app, IIndexManager manager)
        {
            SearcherBase searcher = _iocResolver.Resolve(app.SearcherType) as SearcherBase;
            searcher.Initialize(app, manager);
            return searcher;
        }
    }

经过上述重构,当客户端在看到 SearcherBase 的时候,会发现 ApplicationIndexManager 两个属性并没有Set块,并根据第二种重构方式的Initialize方法推断出,类型初始化的时候,两个属性被赋值。
这样,就增强了SearcherBase的可读性。

何时进行类似重构?

《实现领域驱动设计》这本书中提到,DDD关注的是 核心复杂领域模块 的设计。整个项目中的各个模块有轻重主次之分,只有那些多次被引用、关系核心业务环节的模块才应该做精心的设计,否则会造成过度设计。

原文地址:https://www.cnblogs.com/crayfish/p/5902146.html