【发布时间】:2017-02-14 15:36:40
【问题描述】:
在我正在处理的代码中,我有一个结构,其中代码的某些部分取决于当前的软件会话。软件会话包含多个辅助对象,它们是通过组合注入的依赖项。
一个例子是注入到它的IRepository,它包含对数据存储库的访问。 IRepository 包含一个 DatabaseContext,它再次通过注入的 IDbContext 写入数据库。
SoftwareSession 是唯一注入的通用基础架构,用于一直访问数据库,充当网关。这意味着当我想将一个对象写入数据库时,例如 WriteCar,我将必须实现 3 个接口、2 个委托给组合对象的函数和 1 个带有实现的函数。它在下面的代码片段中得到了澄清。 WriteCar 签名在 3 个接口(IRepository、ISoftwareSession、IDbContext)中定义相同,2 个未实现的地方(Repository、SoftwareSession)仅调用复合对象相关函数和1 个实际实现的地方(IDbContext)
这意味着当我想要重构、移动代码、添加功能或更改函数签名时,我总是需要为一个函数更改 6 个位置。
我认为这为提高可测试性提供了最佳环境,并且它遵循最佳实践,其中软件会话封装了对存储库的访问,而存储库封装了对数据上下文的访问——但我仍然在质疑我们是否可以有更好的方法来编写一次,还是我对下面代码中的某些概念有误解?
在架构上更易于维护的实现方式是什么?甚至可能使用一些巧妙的 lambda 或委托方式来减少为每个新功能编写的代码量?甚至是一些库(如 automapper 简化了 DTO)或工具来简化使用 Visual Studio、Resharper 等从某种模板机制生成此代码?
如果我在这里有一些概念混淆,请告诉我。我知道我的一些同事也有类似的观点,在这种情况下,澄清其他人的误解可能会有所帮助。
public class SoftwareSession : ISoftwareSession
{
...
IRepository repository;
public void WriteCar(Car car){
repository.WriteCar(car);
}
...
}
public interface ISoftwareSession{
...
void WriteCar(Car car);
...
}
public class Repository : IRepository{
...
IDbContext context;
public void WriteCar(Car car){
context.WriteCar(car);
}
...
}
public interface IRepository{
...
void WriteCar(Car car);
...
}
public class MyDbContext : IDbContext{
...
public void WriteCar(Car car){
//The Actual Implementation here.
...
}
...
}
public interface IDbContext{
...
void WriteCar(Car car);
...
}
【问题讨论】:
-
接口也可以继承!为什么没有
ICarWriter接口,然后是IRepository : ICarWriter、ISoftwareSession : ICarWriter等等。 -
我相信问题出在您的软件会话实现中,这违反了单一职责,因为它出现在您的框架中,任何进入数据库、writeCar、writeCustomer 等的东西......必须有一个访问者类。
-
@BarryO'Kane 我同意 - 这是一种重构接口的方式 - 从减少重复代码的角度来看是有意义的。不过,我愿意等待其他可能的简化方法。
-
@Dys1 我也同意你的观点,但这不是我们在使用层时使用的模式(组合优于继承)吗?数据库层与视图模型分离,视图模型使用软件会话作为单独的层/代理,而不是直接访问数据库上下文。如果我们决定更改我们用于 dbcontext 的库,例如EF 到 Ado.net 的一些签名更改,我们只在软件会话中更改它。然而,大多数情况并非如此,我很好奇是否有一种方法可以将其实现为可定制的配置约定
标签: c# oop design-patterns dependency-injection delegation