2011-12-28 10 views
3

私は、さまざまなフルーツのクラスを持っているすべてが同じインターフェイスIFruit実装しています。私は果物のリストを描きたい場合は、私がやっているどのようにリファクタリングメソッド呼び出しは同じように見える?

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

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

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

をそれらのそれぞれが自分の引き出しを持っています次のようになります。

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... 

} 

私のコードを読むと、私は非常に汚いと感じます。
私は12の異なる果物を持っているので、複数のif..elseステートメントがあります。私は現在のプロジェクトでこのステートメントを多くしなければなりません。

DrawFruitsメソッドをリファクタリングする方法はありますか?
私は一種の工場パターンを考えていますが、実際にそれをどうやって行うのか分かりません。
果物のクラスでは、引き出しをプロパティとして使用する必要がありますか?あるいは私はDrawer Factoryメソッドを呼び出すことができますか?

これは私の現在のプロジェクトではたくさんあるパターンで、私を満足させる解決策は見つけられません。

+2

「IFruitDrawer」を使用しないのはなぜですか? –

答えて

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

は、今すぐあなたのドロー・果物は、あなたがDrawerを必要とするだけで時々

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

です、PlotterPrinterので、あなたのIFruit

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

Visitor pattern is a good solution for this以下のような、あまりにもが重いかもしれません。基本的にはあなたがだけではなく、AppleDrawerBananaDrawerなどの1 DrawVisitorを持っており、すべてのあなたのドローコードが一つの場所にきちんとある

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

のための唯一のクラスを持つことになります。あなたは結局必要になるかもしれません。PlotterVisitorPrinterVisiterなど

+0

GetDrawerを使用する代わりに、Drawメソッドを使用できます。 –

+1

@SaeedAmiriはい...OPがDrawのコードをIFruitから分離しているとしたら、私は** Apple、Bananaなど**具体的なクラスだがサロゲートクラスの描画コードの実装を望んでいないと仮定している。 –

+0

Drawerをあなたの実は、GetDrawerを呼び出すかDrawer.Drawを呼び出すと、変更はありません。実際には両方とも同じ依存関係になっています。コードを呼び出すのが難しくなります。 (ちょうど余分な仕事を何も追加しない)。 –

4

おそらく、Drawメソッドを持つ抽象クラスFruitとそれに応じて抽象クラスFruitDrawerを行うことができます。

例えば:


public abstract class Fruit { 
    ... 
} 

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

私はどのようにして正しい引き出しを呼び出しましたか? –

+0

'FruitDrawer.Draw'は、描かれるフルーツの共通要素を持ちます。 @parapura rajkumarが提案したパターンを使用することができます。 –

+0

このようにして、FruitDrawerクラスでif-then-elseを再度実行しますが、何も変更されません。 –

2

あなたは基本的にOpen-Closed Principle違反の標準的な例を逆流が、果物の代わりの形状にしました。

あなたはすべての質問にお答えすることができますが、SOLID Principlesを勉強すれば、はるかに学ぶことができます。

リクエストごとに、あなたのコードに潜んでいきます。

最初に、DrawIFruitインターフェイスにプッシュします。その結果、各果物はすべてを操作するコントローラクラスの代わりに描画する役割を果たします。 は単一責任(S SOLIDのS)違反に終わる可能性がありますが、それは別のリファクタリングになります。ここで重要なことは、果物そのものを描くことで、コントローラが拡張ためオープンである(より多くのフルーツのクラスを追加すること)が、(彼らは自分自身を描画するので、コントローラが変わることはありません)修正ためを閉じました。

あなたは果実を描く単純なループで終わります。

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

コメント「どのません[ブレイク]彼らに」を対処するために...彼らが何であるかを知ること

は、学習のキャリアの最初のステップであり、それらを適用します。それらを壊すのを避ける最も簡単な方法は、テスト駆動開発については非常に厳しいです。あなたが例として挙げたものの多くは、意識的にTDD経由で行うことは非常に難しいでしょう。言い換えれば、TDDを行っているSOLID原則を知っていれば、あなたが投稿したコードで終わることはありません。

+2

私はその質問に尋ねた人でもないし、質問のうち少なくともいくつかにあなたがびっくりしたことをやってみたい。はい、テキストのページを読んで勉強したり、コースを取ったりすることでもっと多くのことを学ぶことができますが、誰もがそれをしたら、このようなウェブサイトには全くポイントがありません。あなたが引用した設計原則と、可能な "修正"(改善された設計)がもたらす可能性があるものを少なくとも要約することを検討してください。 –

+0

真実、私はソリッドの原則を読んでいるので、それは私が私がそれらを壊したことを知っているそれらを読むためです。しかし、私はまだそれらを壊さない方法を知らない! –

+0

@CodyGray:リクエストごとに編集されました。 –

1

私はこのように行うには優れていると思う:あなたは関連の果物で、特定の引き出しのための余分な初期化を実行することができ、このように実際に

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

を:

interface IFruit 
{ 
    void Draw(); 
} 

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

と単純にそれを使用しています。

+0

私はそれを考えました、果物と引き出しが別の層にあるので部分的なクラスを作るだけです。これが最善の方法ですか? –

+0

@ Scorpi0、これは私の心の中にあるものですが、私は最高のものかどうかはわかりませんが、現在利用可能な他の回答と比較して、私は一番良いと思います。実際には、具体的なクラスではなくインターフェースを使ってそれらを分けることができます。 –

関連する問題