2011-05-31 84 views
1

我想确定构建一些代码的最佳方法。我承认这可能是过度的,正在变成比实际更具学术性的东西。有时你无法自拔。有没有一种在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); 

我希望能解释一下。

回答

1

可以使用泛型的具体实施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*/); 
+0

谢谢,我正在尝试此路径。我不喜欢它的一件事(你指出我认为)是由CreateProcessor返回的对象除了对象之外没有共同的祖先。我无法编写与As或Bs一起工作的代码(但不能同时使用这两种代码),而无需投入更通用的代码,在这种情况下,我又回到了开始的地方。 – Jeremy 2011-05-31 18:13:15

+0

您可以从工厂返回一个'IPhotoProcessor '。但工厂方法本身需要该类型参数;这迫使客户知道哪个值用于类型参数。更好的方法是将整个交互封装在另一个对象中,并且客户端不需要担心来自'Process'方法的返回值。 – 2011-05-31 18:31:38

1

在我看来,你的IProcessedPhoto/IPhotoProcessor抽象过于普遍,至少出于你描述的目的。

您可以创建导出接口,每个照片类和处理器(如IProcessedPhotoA/IPhotoProcessorA,和同为B),因此,只有那些实现所需的接口(AB)照片通过调整你的代码到给定的处理器。

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

然而,尽管接口暗示什么,过程仅适用于相应类型的IProcessedPhoto(A和B的照片是不能互换的,他们只是有类似的方法名)

如果它们不能互换以供PhotoProcessor使用,那么您的代码不应该这样对待它们。

+0

我同意最后一点 - 事实上,这是我不喜欢代码的主要原因。 – Jeremy 2011-05-31 16:30:00

+0

谢谢,我正试图调整这个解决方案到我的代码,看看它是否工作。就像你说的,不确定实际代码增加的复杂性是否使得这个工作最好。 – Jeremy 2011-05-31 18:17:03

1

我会试图将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(); 
相关问题