有没有一种在C#中实现此模板方法或策略类模式的优雅方法?
我想确定构建一些代码的最佳方法。我承认这可能是过度的,正在变成比实际更具学术性的东西。有时你无法自拔。有没有一种在C#中实现此模板方法或策略类模式的优雅方法?
让我图谋一个简单的例子:
假设你的类/接口,如:
interface IProcessedPhoto { }
interface IPhotoProcessor
{
IProcessedPhoto Process(byte[] bytes);
void Alter(IProcessedPhoto processedPhoto);
}
class PhotoProcessedWithAMethod : IProcessedPhoto { }
class PhotoProcessedWithBMethod : IProcessedPhoto { }
class AProcessor : IPhotoProcessor
{
IProcessedPhoto Process(byte[] bytes); // Returns PhotoProcessedWithAMethod
void Alter(IProcessedPhoto processedPhoto)
{
var casted = processedPhoto as PhotoProcessedWithAMethod;
// a "B" would crash here.
}
}
class BProcessor : IPhotoProcessor
{
IProcessedPhoto Process(byte[] bytes); // Returns PhotoProcessedWithBMethod
void Alter(IProcessedPhoto processedPhoto)
{
var casted = processedPhoto as PhotoProcessedWithBMethod;
// an "A" would crash here.
}
}
class Algorithm
{
void DoStuff()
{
var processor = ProcessorFactory.CreateProcessor(//stuff);
var processedPhoto = processor.ProcessPhoto(new byte[100]);
processor.Alter(processedPhoto);
}
}
所以基本上我想要的DoStuff()方法来创建一种图像处理器,和呼叫适当的Process方法。但是,尽管接口所暗示的是,进程只适用于相应类型的IProcessedPhoto(A和B照片不可互换,它们只是具有类似的方法名称)。我的真实代码比较复杂,因为每个处理器都有几个特定于它们的类,而且不可互换,但我想执行一组“逻辑”操作,如模板方法。
var artifactA = processor.DoA();
var artifactB = processor.DoB();
var final = processor.Process(artifactA, artifactB);
我希望能解释一下。
可以使用泛型的具体实施IProcessedPhoto
绑定到你的IPhotoProcessor
S:
interface IPhotoProcessor<TProcessedPhoto>
where TProcessedPhoto: IProcessedPhoto {
TProcessedPhoto Process(byte[] bytes);
void Alter(TProcessedPhoto processedPhoto);
}
...
class AProcessor : IPhotoProcessor<PhotoProcessedWithAMethod> { ... }
class BProcessor : IPhotoProcessor<PhotoProcessedWithBMethod> { ... }
的缺点是,你的工厂也需要此信息:
ProcessorFactory.CreateProcessor<PhotoProcessedWithAMethod>(/*stuff*/);
在我看来,你的IProcessedPhoto
/IPhotoProcessor
抽象过于普遍,至少出于你描述的目的。
您可以创建导出接口,每个照片类和处理器(如IProcessedPhotoA
/IPhotoProcessorA
,和同为B
),因此,只有那些实现所需的接口(A
或B
)照片通过调整你的代码到给定的处理器。
我不确定这是否是您的整个代码库的最佳解决方案(我看不到)。我的建议是基于这一点您的帖子:
然而,尽管接口暗示什么,过程仅适用于相应类型的IProcessedPhoto(A和B的照片是不能互换的,他们只是有类似的方法名)
如果它们不能互换以供PhotoProcessor
使用,那么您的代码不应该这样对待它们。
我会试图将Alter方法放在IProcessedPhoto接口上,然后返回一个可以正确更改处理后照片的实现。请注意,您可以将其连接到处理器,并根据需要使用它的方法(未显示)。
public enum PhotoProcessingMethod { A, B }
public interface IProcessedPhoto
{
void Alter();
}
public AProcessedPhoto : IProcessedPhoto
{
...
public void Alter()
{
... alter an A...
}
}
public BProcessedPhoto : IProcessedPhoto
{
...
public void Alter()
{
... alter a B...
}
}
public interface IPhotoProcessor
{
IProcessedPhoto Process(byte[] bytes, PhotoProcessingMethod method);
}
public class PhotoProcessor : IPhotoProcessor
{
public IProcessedPhoto Process(byte[] bytes, PhotoProcessingMethod method)
{
IProcessedPhoto photo;
switch (method)
{
case PhotoProcessingMethod.A:
photo = new AProcessedPhoto(bytes);
break;
case PhotoProcessingMethod.B:
photo = new BProcessedPhoto(bytes);
break;
}
...
return photo;
}
}
用作:
var processor = new PhotoProcessor();
var photoA = processor.Process(bytes, PhotoProcessingMethod.A);
photoA.Alter();
谢谢,我正在尝试此路径。我不喜欢它的一件事(你指出我认为)是由CreateProcessor返回的对象除了对象之外没有共同的祖先。我无法编写与As或Bs一起工作的代码(但不能同时使用这两种代码),而无需投入更通用的代码,在这种情况下,我又回到了开始的地方。 – Jeremy 2011-05-31 18:13:15
您可以从工厂返回一个'IPhotoProcessor'。但工厂方法本身需要该类型参数;这迫使客户知道哪个值用于类型参数。更好的方法是将整个交互封装在另一个对象中,并且客户端不需要担心来自'Process'方法的返回值。 –
2011-05-31 18:31:38