实现一个使用规范来确定要创建的对象类型的工厂
这主要是一个思想实验。 所以这都是示例代码。 我的目标是使用规范模式来消除工厂内巨大的条件代码块。 因此,通过此示例,我有一个 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 类,但这似乎不是很通用,并且还提出了如何将映射器映射到规范的问题。
我还缺少一个小小的飞跃。
This is mainly a thought experiment. So this all is sample code. My goal was to use the specification pattern to eliminate giant blocks of conditional code inside a factory. So with this sample I have a StatusData object that I want to get an implementation of IStatusUpdate that is appropriate for for it.
I have the following set of tests:
[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));
}
My Factory implementation so far looks like this:
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;
}
}
Where I am falling down is once I have discovered a specification that is satisfied by the status object, how do I map that specification to a type that implements IStatusUpdate.. I am stumped.
Someone rightly suggested that I need a mapping of specifications to IStatusUpdate implementers. This mapping seems to be a responsibility of the factory, hanging it off the specification smells like a violation of SRP. I could create a Mapper class that has that responsibility but that doesn't seem very generic and also raises the question how do I map the mapper to the spec.
There is still one little leap here I am missing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
所以我假设我们真的专注于这组线:
并且我假设您在问在当前的形式下如何做到这一点。 看起来 item 应该支持像
然后spec.IsSatisfiedBy 方法可以接受这个接口类型并运行该方法。
换句话说,我想我是说该对象应该带有某种对其内容的描述(就规格而言)。 我猜这是某种列表,但我不确定。 我相信您可能已经想到了这一点,因此如果您可以添加任何有用的内容。
另外,您可以像这样重新排列它,而不是上面的:
这样您就不必使用备受诟病的访问者模式(我认为这就是我之前所描述的)。 它更直接,因为该项目似乎拥有规格,这样您就可以让该项目决定它是否符合规格。
如果您不希望此逻辑保留在对象中(我会理解)并且您正在使用某种属性包(或者您对反射很酷),您可以使用独立规范深入了解对象的详细信息验证器。 事实上,一个独立的验证者一开始可能不是一个坏主意。 我不太确定知道某个规格是否与某个项目匹配的能力是否应该属于单个规格的责任。
So I'm assuming we're really focusing on this set of lines:
and I assume you're asking how in this current form this can be done. It seems like item should support like
Then the spec.IsSatisfiedBy method can take in this interface type and run the method.
In other words I guess I'm saying that the object should carry some sort of description of what it is (in terms of specs). I'm guessing that's a list of some sort but I'm not sure. I'm sure you've probably thought of this so if you can add anything that'd be helpful.
Also, instead of the above maybe you could rearrange it like so:
Then this way you don't have to use the much maligned visitor pattern (I think that's what I was describing before this). It's more direct since the item seems like it would own the specs and this way you're allowing the item to decide if it meets the spec.
If you don't want this logic held within the object (which I would understand) AND you are using a property bag of some sort (or you're cool with reflection) you could dig into the details of the object with an independent spec validator. Actually, an independent validator might not be a bad idea to begin with. I'm not so sure that the ability to know if a spec matches an item is a responsibility that should remain with an individual spec.
如果我理解正确的话,你想要一个实现 ISpecification 的对象,你想要一个实现 IStatusUpdate 的对象吗?
在您的示例中,没有定义这些类型,因此我不知道您可以使用它们之间是否存在任何关系。
但您可能需要一些工厂来保存代码,或者需要一个 ISpecification.GetUpdate() 方法来创建对象。
If I have understood correctly, you want, given an object implementing ISpecification you want an object implementing IStatusUpdate?
In your sample none of these types are defined, so I don't know if there is any relationship between them you could use.
But likely you will either need need some factory to hold the code, or a method ISpecification.GetUpdate() to do the object creation.