有没有一种优雅的方法可以在C#中实现这种模板方法或类似策略的模式

本文关键字:实现 模板方法 模式 策略 一种 有没有 方法 | 更新日期: 2023-09-27 17:58:00

我正在努力决定构建某些代码的最佳方式。我承认,这可能太过分了,而且正在变成一种学术性而非实践性的东西。有时你就是无法控制自己。

让我设计一个简单的例子:

假设您有类/接口,例如:

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方法。然而,不管界面上有什么建议,Process只适用于适当类型的IProcessedPhoto(A和B照片不能互换,它们只是有相似的方法名)。我的实际代码更复杂,因为每个处理器都有几个特定的类,并且不能互换,但我想像模板方法一样执行相同的一组"逻辑"操作。

var artifactA = processor.DoA();
var artifactB = processor.DoB();
var final = processor.Process(artifactA, artifactB);

我希望这能解释它。

有没有一种优雅的方法可以在C#中实现这种模板方法或类似策略的模式

您可以使用泛型将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/IPhotoProcessorAB也是如此),并调整代码,以便只有那些实现所需接口(AB)的照片才能传递给给定的处理器。

我不确定这是否是整个代码库的最佳解决方案(我看不到)。我的建议是基于你帖子中的这一点:

然而,不管界面如何,Process只适用于适当类型的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();