这主要是一个思想实验。所以这一切都是示例代码。我的目标是使用规范模式来消除工厂内的巨大条件代码块。因此,对于此示例,我有一个StatusData对象,我想获得适合它的IStatusUpdate实现。
我有以下一组测试:
[TestMethod]
public void Factory_Interface_Should_Return_IStatusUpdate()
{
var factory = MockRepository.GenerateMock<IUpdateFactory<StatusData>>();
var obj = MockRepository.GenerateStub<IStatusUpdate>();
var data = new StatusData();
factory.Stub(x => x.Get(data)).Return(obj);
var item = factory.Get(data);
Assert.IsInstanceOfType(item, typeof(IStatusUpdate));
}
[TestMethod]
public void StatusUpdateFactory_Should_Return_IStatusUpdate()
{
var factory = new StatusUpdateFactory();
var data = new StatusData();
var item = factory.Get(data);
Assert.IsInstanceOfType(item, typeof(IStatusUpdate));
}
[TestMethod]
public void StatusUpdateFactory_Should_Return_NewStatusUpdate_When_Status_Is_New()
{
var data = new StatusData(Status.New);
var factory = new StatusUpdateFactory();
var item = factory.Get(data);
Assert.IsInstanceOfType(item, typeof(NewStatusUpdate));
}
到目前为止,我的工厂实施如下:
public class StatusUpdateFactory:IUpdateFactory<StatusData>
{
public IStatusUpdate Get(StatusData item)
{
IList<ISpecification<StatusData>> specs = GetSpecifications();
foreach (var spec in specs)
{
if (spec.IsSatisfiedBy(item))
//how do I do this?
return new NewStatusUpdate();
}
return null;
}
private IList<ISpecification<StatusData>> GetSpecifications()
{
var returnList = new List<ISpecification<StatusData>>();
var specTypes = this.GetType().Assembly.GetTypes()
.Where(z => z.IsInstanceOfType(typeof(ISpecification<StatusData>)))
.ToList();
specTypes.ForEach(x => returnList.Add(Activator.CreateInstance(x) as ISpecification<StatusData>));
return returnList;
}
}
我倒下的地方是,一旦我发现了状态对象满足的规范,我该如何将该规范映射到实现IStatusUpdate的类型..我很难过。
有人正确地建议我需要将规范映射到IStatusUpdate实现者。这种映射似乎是工厂的责任,使其脱离规范,闻起来像违反了SRP。我可以创建一个具有该职责的Mapper类,但这似乎不是非常通用的,并且还提出了如何将映射器映射到规范的问题。
我在这里还有一个小小的飞跃。
答案 0 :(得分:2)
如果我理解正确,你想要一个实现ISpecification的对象,你想要一个实现IStatusUpdate的对象吗?
在您的样本中,没有定义任何类型,因此我不知道您可以使用它们之间是否存在任何关系。
但是你可能需要一些工厂来保存代码,或者需要一个方法ISpecification.GetUpdate()来创建对象。
答案 1 :(得分:1)
所以我假设我们真的专注于这一系列:
if (spec.IsSatisfiedBy(item))
return new NewStatusUpdate();
我猜你在问这个目前的形式如何做到这一点。似乎项目应该像
一样支持interface ISpecSupport<T>
{
bool ItemSpecsContain(ISpecification<T> spec);
}
然后spec.IsSatisfiedBy方法可以接受此接口类型并运行该方法。
换句话说,我想我说的是对象应该对它的内容进行某种描述(就规格而言)。我猜这是一个列表,但我不确定。我相信如果你能添加任何有用的东西,你可能已经想到了这一点。
另外,也许你可以像上面那样重新安排它:
if (item.Satisfies(spec))
return new NewStatusUpdate();
然后通过这种方式你不必使用备受诟病的访客模式(我认为这是我之前所描述的)。它更直接,因为该项似乎拥有规格,这样你就可以让物品决定它是否符合规格。
如果你不希望这个逻辑保存在对象中(我会理解)并且你正在使用某种属性包(或者你很反感)你可以深入研究对象的细节独立的规范验证器。实际上,一个独立的验证器可能不是一个坏主意。我不太确定知道某个规格是否符合某个项目的能力是一个应该保留在个别规范中的责任。