【发布时间】:2015-01-29 13:54:12
【问题描述】:
情况
我正在构建一个 C# Web 应用程序,我想将我的应用程序配置建模为显式依赖项,以通过服务的构造函数提交,而不是在每个类中直接依赖 System.Configuration.ConfigurationManager。这在过去确实经常咬我,所以我希望依赖关系是明确的,以便项目的下一个维护者(可能是未来的我)不必猜测我的服务从哪里获取配置设置 - 最重要的是更多 TDD 友好。此外,我目前正在阅读Eric Evan's Domain Driven Design,我真的很想接受他的DDD 方法。
我开始对配置类和相应的值对象进行建模以避免Primitive Obsession,但我在途中遇到了一些问题,我不确定如何正确处理它们。这是我目前的做法:
// Role interface that can be requested via constructor injection
interface IAppConnectionStringsConfig
{
OleDbConnectionString AuthenticationConnectionString { get; }
}
// A base class for handling common functionality like
// parsing comma separated lists or default values
class abstract AppConfigBase
{
protected string GetStringAppSetting(string key)
{
// Get the appropriate string or a default value from
// System.Configuration.ConfigurationManager
return theSettingFromSomeConfigSource;
}
}
// A value object for OLEDB connection strings that also has a
// convenient implicit conversion to string
class OleDbConnectionString
{
public readonly string Value;
public OleDbConnectionString(string connectionString)
{
Contract.Requires(connectionString != null);
this.VerifyStructure(connectionString);
this.Value = connectionString;
}
private void VerifyStructure(string text)
{
Contract.Requires(text != null);
// Verify that the given string fulfills the special
// needs of an OleDbConnectionString (including Provider=...)
if (!/* isValidOleDbConnectionString */)
{
throw new FormatException();
}
}
public implicit operator string(ConnectionString conn)
{
return conn.Value;
}
}
// The actual app config that implements our role interface
class AppConfig : AppConfigBase, IAppConnectionStringsConfig
{
public OleDbConnectionString AuthenticationConnectionString
{
get
{
return new OleDbConnectionString(this.GetStringAppSetting("authconn"));
}
}
}
问题
我知道构造函数的逻辑应该是最小的,从构造函数调用虚方法不是一个好主意。我的问题如下:
- 1) 我应该将
OleDbConnectionString的验证逻辑放在哪里?我真的很想防止在无效状态下创建值对象-这在日常工作中非常有用:-)- 我觉得这是应该由类本身拥有的域逻辑,但另一方面,构造函数应该尽可能少做 - 字符串解析会不会太多或者这样可以吗?李>
- 我可以创建一个验证器,但我肯定必须通过构造函数提交它才能正确测试该东西,然后我必须手动连接它或使用工厂(我肯定是not using a Service Locator)。最重要的是,验证现在将隐藏在单独的服务中;我不会有时间耦合,因为构造函数需要验证器,但看起来仍然不正确。
- 2) 我想知道是否适合制作 DDD 值对象@987654331@?它们 - 顾名思义 - 代表单个值,并且该值是不可变的。但它们会以验证的形式包含业务逻辑
- 3) 是否可以使用属性来检索连接字符串?如果字符串的格式无效,它可能会引发异常。此外,完全有可能将实现从读取 xml 配置文件更改为查询数据库。
- 4) 欢迎设计中的任何其他 cmets!
附带说明一下,我已经在使用 Code Contracts 并且有一种方法可以使用 specify object invariants 但我不知道这是否真的是一个好主意,因为这些合同是可选的,并且在这种情况下它们是不活动的,不变量不再受到积极保护。我不确定这一点,出于开发目的及早发现错误可能没问题,但对于生产来说它似乎关闭了。
谢谢!
【问题讨论】:
标签: c# inheritance domain-driven-design value-objects