域/业务层的设计模式选择

时间:2014-03-05 09:29:38

标签: c# design-patterns composition facade

我试图避免这个类ContentDomain成为神类并将功能隔离到特定的类(跟随SRP),就像这样

ContentDomain

 public class ContentDomain : IContentDomain
{
    private ISolutionDomain solutionDomain;
    private IServiceDomain serviceDomain;
    private IPhaseDomain phaseDomain;

    public ContentDomain(IUnitOfWork _unitOfWork)
    {
        this.solutionDomain = new SolutionDomain(_unitOfWork);
        this.serviceDomain = new ServiceDomain(_unitOfWork);
        this.phaseDomain = new PhaseDomain(_unitOfWork);
    }

    public ISolutionDomain SolutionDomain { get { return solutionDomain; } }
    public IServiceDomain ServiceDomain { get { return serviceDomain; } }
    public IPhaseDomain PhaseDomain { get { return phaseDomain; } }
}

特定域类之一

public class SolutionDomain : BaseDomain, ISolutionDomain
{
    public SolutionDomain(IUnitOfWork _unitOfWork)
        : base(_unitOfWork)
    {

    }

    public IEnumerable<Solution> GetAllSolutions()
    {
        return base.GetAll<Solution>(sol => sol.IsActive == true).OrderBy(rec => rec.Name).Select(rec => rec).ToList();
    }
}

现在我的控制器只知道ContentDomain,并在需要时调用SolutionDomain / ServiceDomain / PhaseDomain中的特定方法:

public ContentController(IContentDomain domain, ICurrentUser currentUser)
        : base(domain, currentUser)
    {

    }


public ActionResult Home()
    {
        var myServices = domain.ServiceDomain.GetServicesWithDetails(rec => rec.CreatedBy == currentUser.Name);
        var viewModelCollection = myServices.Select(service => new DashboardViewModel(service, domain));

        if (currentUser.IsInRole("SU"))
            return View("Home_SU", viewModelCollection);

        else if (currentUser.IsInRole("Reviewer"))
            return View("Home_Reviewer", viewModelCollection);

        else return View("Home", viewModelCollection);
    }

注意Home()

中的第一个语句
domain.ServiceDomain.GetServicesWithDetails(rec => rec.CreatedBy == currentUser.Name);

我发现自己在ContentDomain类中混合了Facade和Composition。

现在的问题是 -

  1. 使用合成通过Facade公开特定的域功能是否合理?
  2. 如果没有,可能会有什么问题?
  3. 我有可能通过这种方法违反任何SOLID原则吗?

1 个答案:

答案 0 :(得分:4)

  

使用合成通过Facade公开特定的域功能是否合理?

根据示例,ContentDomain类和IContentDomain接口不提供任何功能。更好的组合形式是抛弃两者,并根据所需的最小依赖关系定义控制器和其他客户端:

private readonly IServiceDomain serviceDomain;
private readonly ICurrentUser currentUser;

public ServiceController(IServiceDomain serviceDomain, ICurrentUser currentUser)
{
    this.serviceDomain = serviceDomain;
    this.currentUser = currentUser;
}

public ActionResult Home()
{
    var myServices = this.serviceDomain.GetServicesWithDetails(
        rec => rec.CreatedBy == currentUser.Name);
    var viewModelCollection = myServices.Select(
        service => new DashboardViewModel(service, domain));

    if (this.currentUser.IsInRole("SU"))
        return View("Home_SU", viewModelCollection);

    else if (this.currentUser.IsInRole("Reviewer"))
        return View("Home_Reviewer", viewModelCollection);

    else return View("Home", viewModelCollection);
}

这是 true Composition ,因为您使用ServiceControllerIServiceDomain的实现撰写ICurrentUser

  

如果没有,可能会有什么问题?

IContentDomain的设计存在一些问题。

  • 维护起来比较困难,因为每次要向IContentDomain添加其他服务时,都需要将其作为(只读)属性添加到接口,这是一个重大变化。
  • 可能会隐藏游戏中存在的依赖性超过了显而易见的依赖性。查看ServiceController的建议构造函数,看起来好像只有两个依赖项传递给ServiceController,但实际的数字是4。平面构造函数注入的一大好处是it makes it quite clear when the Single Responsibility Principle is violated
  • 违反了接口隔离原则(见下文)。
  

我有可能通过这种方法违反任何SOLID原则吗?

是的,这种设计违反了SOLID,因为它至少违反了接口隔离原则,该原则规定不应强迫客户端依赖于他们不使用的成员

但是,在上面的示例中,ServiceController被强制依赖SolutionDomainPhaseDomain属性,尽管它不使用它。

这种设计很可能会导致违反单一责任原则,因为您传递给客户的功能越多,它本身就越倾向于做,而不是依赖于其他部分。系统

它也可能导致违反Liskov替换原则(LSP),因为一般的趋势是你在接口上定义的成员越多,就越难以遵守LSP。通常,Header Interfaces往往会导致LSP违规。