【发布时间】:2011-03-31 12:45:06
【问题描述】:
好的,我将尝试简短而直截了当。我正在尝试开发一个可测试并支持依赖注入的松散耦合的多层服务应用程序。这是我所拥有的:
在服务层,我有一个 StartSession 方法,它接受启动会话所需的一些关键数据。我的服务类是一个外观,并委托给注入到服务类构造函数中的 ISessionManager 接口的一个实例。
我在数据访问层使用存储库模式。所以我有一个 ISessionRepository,我的域对象可以使用它,并且我使用当前的数据访问技术来实现。 ISessionRepository 具有 GetById、Add 和 Update 方法。
由于我的服务类只是一个门面,我认为可以肯定地说我的 ISessionManager 实现是我的体系结构中的实际服务类。此类与我的 Session 域/业务对象协调操作。这就是空壳游戏和问题所在。
在我的 SessionManager 类(具体的 ISessionManager)中,我是这样实现 StartSession 的:
public ISession StartSession(object sessionStartInfo)
{
var session = Session.GetSession(sessionStartInfo);
if (session == null)
session = Session.NewSession(sessionStartInfo);
return session;
}
这段代码有三个问题:
- 首先,显然我可以将此逻辑移动到我的 Session 类中的 StartSession 方法中,但我认为这会破坏 SessionManager 类的目的,然后它只是成为第二个外观(或者它仍然被视为协调器?)。唉,贝壳游戏。
- 其次,SessionManager 对 Session 类具有紧密耦合的依赖关系。我考虑创建一个可以注入到 SessionManager 中的 ISessionFactory/SessionFactory,但是我会在工厂内部进行相同的紧耦合。但是,也许没关系?
- 最后,在我看来,真正的 DI 和工厂方法不能混合使用。毕竟,我们要避免“新建”一个对象的实例,而让容器将实例返回给我们。真正的 DI 说我们不应该直接引用容器。那么,如何将具体的 ISessionRepository 类注入到我的 Session 域对象中呢?我是否将其注入工厂类,然后在构造新实例时手动将其传递给 Session(使用“new”)?
请记住,这也只是一项操作,我还需要执行其他任务,例如保存会话、根据各种标准列出会话以及在我的解决方案中使用其他域对象。另外,Session 对象还封装了授权、验证等业务逻辑,所以(我认为)它需要存在。
我想要完成的关键不仅是功能性的,而且是可测试的。我正在使用 DI 来打破依赖关系,因此我们可以使用 mock 轻松实现单元测试,并让我们能够对具体实现进行更改,而无需在多个领域进行更改。
您能否帮助我了解此类设计的最佳实践以及如何才能最好地实现我的目标,以实现可靠的 SOA、DDD 和 TDD 解决方案?
更新
我被要求提供一些额外的代码,尽可能简洁:
[ServiceContract()]
public class SessionService : ISessionService
{
public SessionService(ISessionManager manager) { Manager = manager; }
public ISessionManager Manager { get; private set; }
[OperationContract()]
public SessionContract StartSession(SessionCriteriaContract criteria)
{
var session = Manager.StartSession(Mapper.Map<SessionCriteria>(criteria));
return Mapper.Map<SessionContract>(session);
}
}
public class SessionManager : ISessionManager
{
public SessionManager() { }
public ISession StartSession(SessionCriteria criteria)
{
var session = Session.GetSession(criteria);
if (session == null)
session = Session.NewSession(criteria);
return session;
}
}
public class Session : ISession
{
public Session(ISessionRepository repository, IValidator<ISession> validator)
{
Repository = repository;
Validator = validator;
}
// ISession Properties
public static ISession GetSession(SessionCriteria criteria)
{
return Repository.FindOne(criteria);
}
public static ISession NewSession(SessionCriteria criteria)
{
var session = ????;
// Set properties based on criteria object
return session;
}
public Boolean Save()
{
if (!Validator.IsValid(this))
return false;
return Repository.Save(this);
}
}
而且,很明显,我认为不需要显示 ISessionRepository 接口和具体的 XyzSessionRepository 类。
第二次更新
我在 Session 域对象中添加了 IValidator 依赖项,以说明还有其他组件在使用中。
【问题讨论】:
-
您能发布更多代码吗?不清楚每个类的作用——例如,Session 类是被注入的服务类,还是存在三个不同的类(Session、SessionManager、SessionService)?
-
Session 类是静态的吗?同样,多一点代码会澄清很多。
-
Session 是域对象(根)。
标签: c# dependency-injection tdd domain-driven-design soa