简体   繁体   English

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

[英]Is there an elegant way to implement this template method- or strategy-like pattern in C#?

I am trying to decide the best way to structure some code.我正在尝试确定构建某些代码的最佳方式。 I will admit this may be overboard and is turning into something more academic than practical.我承认这可能太过分了,而且正在变成一种学术性而非实用性的东西。 Sometimes you just cannot help yourself.有时你就是无法帮助自己。

Let me contrive a simple example:让我设计一个简单的例子:

Suppose you have classes/interfaces such as:假设您有类/接口,例如:

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);
    }
}

So basically I want the DoStuff() method to create one kind of image processor, and call the appropriate Process method.所以基本上我希望 DoStuff() 方法创建一种图像处理器,并调用适当的 Process 方法。 However, despite what the interface suggests, Process only works on an IProcessedPhoto of the appropriate type (A and B photos are NOT interchangeable, they just have similar method names).然而,尽管界面提示了什么,Process 仅适用于适当类型的 IProcessedPhoto(A 和 B 照片不可互换,它们只是具有相似的方法名称)。 My real code is more complicated in that each processor has several classes specific to them and not interchangeable, but I want to perform the same set of "logical" operations like a template method.我的真实代码更复杂,因为每个处理器都有几个特定于它们的类并且不可互换,但我想像模板方法一样执行相同的一组“逻辑”操作。

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

I hope that explains it.我希望能解释它。

It seems to me that your IProcessedPhoto / IPhotoProcessor abstraction is too generalized, at least for the purposes you describe.在我看来,您的IProcessedPhoto / IPhotoProcessor抽象过于笼统,至少对于您描述的目的而言。

You could create derived interfaces for each of the photo classes and processors (eg IProcessedPhotoA / IPhotoProcessorA , and same for B ), and adjust your code so that only those photos that implement the required interface ( A or B ) are passed to a given processor.您可以为每个照片类和处理器(例如IProcessedPhotoA / IPhotoProcessorAB相同)创建派生接口,并调整您的代码,以便只有那些实现所需接口( AB )的照片被传递给给定的处理器.

I'm not sure whether that's the best solution for your entire codebase (which I can't see).我不确定这是否是您整个代码库的最佳解决方案(我看不到)。 My suggestion is based on this bit of your post:我的建议是基于你的这篇文章:

However, despite what the interface suggests, Process only works on an IProcessedPhoto of the appropriate type (A and B photos are NOT interchangeable, they just have similar method names)但是,尽管界面提示了什么,Process 仅适用于适当类型的 IProcessedPhoto(A 和 B 照片不可互换,它们只是具有相似的方法名称)

If they're not interchangeable for the purpose of being used by a PhotoProcessor , your code shouldn't treat them as such.如果它们不可互换以供PhotoProcessor使用,则您的代码不应这样对待它们。

I would be tempted to put the Alter method on the IProcessedPhoto interface, then return an implementation that can correctly alter the processed photo.我很想将 Alter 方法放在 IProcessedPhoto 接口上,然后返回一个可以正确更改已处理照片的实现。 Note you could connect it to the processor as well and use methods from it if needed (not shown).请注意,您也可以将其连接到处理器,并在需要时使用其中的方法(未显示)。

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;
     }
}

Used as:用作:

var processor = new PhotoProcessor();
var photoA = processor.Process( bytes, PhotoProcessingMethod.A );
photoA.Alter();

You can use generics to bind the specific implementation of IProcessedPhoto to your IPhotoProcessor s:您可以使用 generics 将IProcessedPhoto的具体实现绑定到您的IPhotoProcessor

interface IPhotoProcessor<TProcessedPhoto> 
  where TProcessedPhoto: IProcessedPhoto {

  TProcessedPhoto Process(byte[] bytes);
  void Alter(TProcessedPhoto processedPhoto);

}

...

class AProcessor : IPhotoProcessor<PhotoProcessedWithAMethod> { ... }

class BProcessor : IPhotoProcessor<PhotoProcessedWithBMethod> { ... }

The downside is that your factory also needs this information:缺点是你的工厂也需要这些信息:

ProcessorFactory.CreateProcessor<PhotoProcessedWithAMethod>(/*stuff*/); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM