2011-05-31 91 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(); 
相關問題