C# 域/业务层的设计模式选择
我试图避免此类ContentDomain成为一个God类,并将功能隔离到特定类中(遵循SRP),如下所示 ContentDomain:C# 域/业务层的设计模式选择,c#,design-patterns,composition,facade,C#,Design Patterns,Composition,Facade,我试图避免此类ContentDomain成为一个God类,并将功能隔离到特定类中(遵循SRP),如下所示 ContentDomain: public class ContentDomain : IContentDomain { private ISolutionDomain solutionDomain; private IServiceDomain serviceDomain; private IPhaseDomain phaseDomain; public
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();
}
}
注意Home()中的第一条语句
我发现自己在ContentDomain类中混合了Facade和Composition
现在问题是-
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);
}
这是真正的组合,因为您使用IServiceDomain
和ICurrentUser
的实现组合ServiceController
如果没有,可能有什么问题
IContentDomain
的设计存在几个问题
- 它更难维护,因为每次您想向
添加另一个服务时,都需要将其作为(只读)属性添加到接口中,这是一个突破性的更改IContentDomain
- 它可能隐藏了更多的依赖性,而不是显而易见的。查看提议的
构造函数,看起来只有两个依赖项被传递到ServiceController
,但实际数量是四个。平面构造函数注入的最大好处之一是ServiceController
- 它违反了接口隔离原则(见下文)
ServiceController
被强制依赖于SolutionDomain
和PhaseDomain
属性,尽管它没有使用它
这种设计也很可能会违反单一责任原则,因为您向客户传递的功能越多,客户就越倾向于自行完成,而不是依赖系统的其他部分
它还可能导致违反Liskov替换原则(LSP),因为有一种普遍趋势,即在接口上定义的成员越多,就越难遵守LSP。通常,这会导致LSP冲突。我发现很难理解这个问题,因为它太抽象了(一切都是一个接口)。除了
currentUser.Name
之外,我真的看不出您正在公开什么“特定域功能”。你的问题3太宽泛了。设计是各种各样的折衷,所以答案是你最有可能(在一个复杂的项目中)在某个地方违反实体。TL;DR您的问题需要更具体才能得到答案。SolutionDomain类表示特定的域功能,该功能公开为domain.solutionDomainHanks@Mark。这很有帮助。但是我的ServiceController(现在的ContentController)需要的不仅仅是ServiceDomain。它需要SolutionDomain、PhasedMain等的功能。我不确定这些域类型是否应该注入到我的ContentController中。这就是我在ContentDomain类中包装所有特定域类型的原因。有人帮忙吗?请参阅我的编辑:ServiceController重命名为ContentController。您是否建议在我的客户端应用程序中为ServiceDomain、SolutionDomain和PhaseDomain设置单独的使用者(控制器)?是的,通过这种方式,它更接近ISP(和SRP),但随后它变成了一个ASP.NET MVC特定的问题。如果您的控制器有太多依赖项,您希望了解它,因为这是一个问题(它表明违反了SRP)。这是上面的第二个要点。在IContentDomain
后面隐藏许多依赖项并不能解决这个问题:它只会隐藏它;一开始就很难发现你有问题。听起来你可以从引入Facade服务中获益:这是一个很好的答案,有一些宝贵的链接,就像Facade Services
@MarkSeemann,一篇关于聚合的好文章。但我更倾向于将客户端的每个域功能隔离到单独的控制器中。例如,带有ISolutionDomain注入的SolutionController。
domain.ServiceDomain.GetServicesWithDetails(rec => rec.CreatedBy == currentUser.Name);
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);
}