2011-12-28 42 views
3

我有不同的果類,都實現了相同的接口IFruit如何重構方法調用看起來像一樣?

public interface IApple : IFruit{ } 
public interface IBanana : IFruit{ } 
public interface ICarrot: IFruit{ } 

他們每個人都有自己的抽屜:

public class AppleDrawer 
{ 
    public void Draw(IApple apple, Graphics graphics){} 
} 

public class BananaDrawer 
{ 
    public void Draw(IBanana banana, Graphics graphics){} 
} 

如果我想畫水果的清單,我做以下

public void DrawFruits(List<IFruit> fruits, Graphics graphics) 
{ 
    foreach(var fruit in fruits) 
    { 
     if(fruit is IBanana) 
     { 
      var banana = (IBanana)fruit; 
      var drawer = new BananaDrawer(); 
      drawer.Draw(banana, graphics); 
     } 
     else if(fruit is IApple) 
     { 
      var apple = (IApple)fruit; 
      var drawer = new AppleDrawer(); 
      drawer.Draw(banana, graphics); 
     } 
     etc... 

} 

當我閱讀我的代碼時,我感到非常骯髒。
我的問題是多個if..else聲明,因爲我有12個不同的水果,我必須在我當前的項目中做很多這個聲明。

有沒有辦法重構我的DrawFruits方法?
我在想一種工廠模式,但我真的不知道該怎麼做。
我的水果班是否必須將抽屜作爲一個財產?或者,也許我可以調用Drawer Factory方法?

這是一種模式,我在當前的項目中發現了很多,我找不到滿足我的解決方案。

+2

爲什麼不只是使用'IFruitDrawer'? – 2011-12-28 15:46:25

回答

5

一種方法是對你IFruit

public interface IFruit 
{ 
    BaseDrawer GetDrawer(); 
} 

一個GetDrawerBaseDrawer接口

public interface BaseDrawer 
{ 
    void Draw(IFruit fruit, Graphics graphics); 
}. 

public class AppleDrawer : BaseDrawer 
{ 
    public void Draw(IFruit apple, Graphics graphics) { } 
} 

public class BananaDrawer : BaseDrawer 
{ 
    public void Draw(IFruit banana, Graphics graphics) { } 
} 

現在你的平局水果簡直是

public void DrawFruits(List<IFruit> fruits, Graphics graphics) 
    { 
     foreach (var fruit in fruits) 
     { 
      var drawer = fruit.GetDrawer(); 
      drawer.Draw(fruit, graphics); 
     } 
    } 

有時你需要一個DrawerPlotterPrinter所以你IFruit可能過於重像下面

public interface IFruit 
{ 
    BaseDrawer GetDrawer(); 
    BasePrinter GetPrinter(); 
    BasePlotter GetPlotter(); 
} 

Visitor pattern is a good solution for this。基本上,你將有

public interface iFruit 
    { 
     void Accept(FruitVisitor visitor); 
    } 

只有一個類爲所有可能的繪製訪問

public class DrawVisitor : FruitVisitor 
    { 
     public override void Visit(Apple apple) 
     { 
     //draw the apple 
     } 

     public override void Visit(Banana banana) 
     { 
     // draw the banana 
     } 
    } 

在這裏你只需要一個DrawVisitor,而不是AppleDrawerBananaDrawer等和所有的抽獎代碼是整齊地在一個地方。您可能最終需要PlotterVisitor,PrinterVisiter

+0

而不是有GetDrawer,你可以有一個繪製方法。 – 2011-12-28 15:58:06

+1

@SaeedAmiri是...如果OP已將Draw代碼與IFruit分開,我假設他不希望在** Apple,Banana等等**具體課程中實施繪圖代碼,但在替代課程中 – 2011-12-28 16:00:06

+0

在您使用的所有抽屜水果,如果您調用GetDrawer或調用Drawer.Draw,則不會發生變化,實際上它們都具有相同的依賴關係。但是您的選擇使得更難調用代碼。 (只不過是增加了額外的工作)。 – 2011-12-28 16:04:30

4

也許你可以做一個抽象類FruitDraw方法,並相應地抽象類FruitDrawer

例如:


public abstract class Fruit { 
    ... 
} 

public abstract class FruitDrawer { 
    public void Draw(Fruit f, Graphics g) 
    { 
    ... 
    } 
} 
+0

那我怎麼稱呼右邊的抽屜呢? – 2011-12-28 15:51:51

+0

'FruitDrawer.Draw'將具有繪製任何水果的共同元素。你可以使用建議的模式@parapura rajkumar。 – 2011-12-28 15:54:54

+0

以這種方式,你將在FruitDrawer類中擁有if-then-else,沒有什麼可以改變的。 – 2011-12-28 15:55:02

2

你基本上反芻的Open-Closed Principle違反但水果代替形狀的典型例子。

你可以深入瞭解你的所有問題,但是如果你學習SOLID Principles,你會學到更多東西。

根據要求,我會深入您的代碼。

首先,我會推DrawIFruit接口,以便每個水果負責繪製自己,而不是控制器類操縱一切。你可能結束了單一責任(S在SOLID)侵犯,但這將是另一個重構。這裏最重要的是,水果畫自己和控制器開放延期(增加更多的水果類),但關閉進行修改(因爲他們自己繪製,控制器永遠不會改變)。

然後你最終得到一個簡單的循環繪製你的水果。

foreach(var fruit in fruits) 
    fruit.Draw(...); 

,解決「如何不[破]他們」評論...

知道他們什麼是對學習的職業生涯,並應用它們的第一步。避免破壞它們的最簡單方法(並非簡單)對測試驅動開發非常嚴格。作爲例子,你所做的很多事情都很難通過TDD自覺地做。換句話說,如果您知道執行TDD的SOLID原理,那麼您將不會收到您發佈的代碼。

+2

我甚至不是那個問這個問題的人,而且*我還是會更喜歡你至少解決一些問題。是的,通過閱讀和研究網頁文本或學習課程,你會學到更多東西,但如果每個人都這樣做,那麼對於像這樣的網站來說就沒有多少意義了。至少考慮一下總結你引用的設計原則,以及可能的「修復」(改進設計)可能需要什麼。 – 2011-12-28 15:57:12

+0

的確如此,因爲我讀過固體原理,這是因爲我讀過它們,我知道我打破了它們。但我仍然不知道如何破壞它們! – 2011-12-28 16:04:05

+0

@CodyGray:根據您的要求進行編輯。 – 2011-12-28 16:09:10

1

我認爲是更好地做到這樣的:

interface IFruit 
{ 
    void Draw(); 
} 

class Banana : IFruit 
{ 
    void Draw() 
    { 
     BananaDrawer drawer = new BananaDrawer(); 
     drawer.Draw(); 
    } 
} 

,並簡單地使用它:

foreach(var fruit in fruits) 
    fruit.Draw(); 

其實這樣你可以在相關的果實特異性抽屜運行額外的初始化。

+0

我已經想到了,我只需要做一個部分課,因爲水果和抽屜在不同的層。這是最好的方法嗎? – 2011-12-28 15:53:40

+0

@ Scorpi0,這就是我腦中所想到的,我不知道是不是最好的,但是與其他目前可用的答案比較,我認爲是最好的答案。事實上,你可以通過使用接口而不是具體類來分開它們,我並沒有這樣做,只是爲了簡化主要部分。 – 2011-12-28 15:59:05

相關問題