2017-10-19 12 views
1

以下の再帰関数のif文をポリモフィズムに置き換えたいと思います。私はそれについてたくさん読ん条件をポリモフィズムに置き換える方法

、いくつかのユーチューブの動画を参照してくださいが、それでも、実際には、このタスクをより困難にするもの

(つまり、この記事の目的のために簡素化されました)私のコードでそれを行う方法を見ることができません私は、関数の初めでのforeachなステートメントと再帰呼び出し多型が型に基づいている

public void FlattenXml(XElement xml, string id = null) 
{ 
    var elements = xml.Elements().ToList(); 
    foreach (var element in elements) 
    { 
     if (element.Name == "name1") 
     { 
      Func1(); 
     } 
     if (element.Name == "name2") 
     { 
      Func2(); 
     } 
     if (element.Name == "name3") 
     { 
      DoSomethingElse(); 
      FlattenXml(content, tempId); 
      Func3(); 
     } 
     else 
     { 
      DoSomethingCompletelyDifferent(); 
      FlattenXml(element, id); 
     } 
    } 
    xml.Elements("name3").Remove(); 
} 
+0

あなたは、 "polimorphism"を置き換えることによって何を意味するのかを明確にすることはできますか? – Evk

+0

https://refactoring.guru/replace-conditional-with-polymorphism – Limbo

+0

このリファクタリングは実際にはあまり適していません。本当に欲しいのであれば、たくさんのクラスを作成できますが、この特定のケースではコードは改善されません。 – Evk

答えて

3

あなたは、コードの美しさと、その後のデザインパターンを使用する場合はI多態性、戦略パターン、パターン検索を使用することをお勧めします。

それは、コードの強化と再利用性の利点を提供します。コード例以下

public interface ISomeOperation 
{ 
    string DoOperation(string data); 
} 

public class OperationA : ISomeOperation 
{ 
    public string DoOperation(string data) 
    { 
     //implemention. 
     return data; 
    } 
} 

public class OperationB : ISomeOperation 
{ 
    public string DoOperation(string data) 
    { 
     //implemention. 
     return data; 
    } 
} 

public class OperationC : ISomeOperation 
{ 
    public string DoOperation(string data) 
    { 
     //implemention. 
     return data; 
    } 
} 

public class OperationD : ISomeOperation 
{ 
    public string DoOperation(string data) 
    { 
     //implemention. 
     return data; 
    } 
} 

public class OperationContext 
{ 
    private readonly Dictionary<string, ISomeOperation> _operationStrategy = new Dictionary<string, ISomeOperation>(); 

    public OperationContext() 
    { 
     _operationStrategy.Add("name1", new OperationA()); 
     _operationStrategy.Add("name2", new OperationB()); 
     _operationStrategy.Add("name3", new OperationC()); 
     _operationStrategy.Add("name4", new OperationD()); 
    } 

    public string GetOperationData(string searchType, string data) 
    { 
     return _operationStrategy[searchType].DoOperation(data); 
    } 
} 

//ドライバコード:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var operationContext = new OperationContext(); 
     var elements = xml.Elements().ToList(); 
     foreach (var element in elements) 
     { 
      operationContext.GetOperationData(element.Name, element); 
     } 
    } 
} 

ノード:複数の方法は、1つの方法で呼び出されるべきです。

+1

唯一のものはのOperationContextのconstractorは新しい名前が追加されますように成長し続けるということですが、あなたがのOperationContextコンストラクタの方法に辞書の操作に追加することを移動することができ、私は – Limbo

+0

を何をしたいのかにかなり近いです。次に、そのメソッドをコンストラクタに呼び出すことができます。 –

0

助けを

感謝の存在です。共通の基本型を持つオブジェクトの型に基づいて、異なる関数(あなたの場合はifブロックの文)を実行することができます。

あなたの場合、文字列に基づいて異なることをしたいと思っています。したがって、文字列から型を作成し、多態性を使用するか、文字列から関数(例:ラムダ式、またはC#のアクション)にマップするためのマップ(DictionaryというC#で)を使用します。さまざまな機能の複雑さと "nameN"の実際の意味に応じて、どちらか一方を選択します。

再帰関数は、あるケースではベースオブジェクトの一部であるか、または他のケースではラムダから呼び出される必要があります。

1

この場合、多型は「型」と「振る舞い」の概念によって理解されます。 3つの "名前"は3つの異なるタイプを示しますが、 "else"もあります。したがって、4つのタイプがあります。

(質問 - ifは完全なif/elseチェーンになりますか?このコードでは、elseが "name1"と "name2"に対して実行されます。 。)

理解することが少し楽にするために、このコードを考えてみます。

public void FeedAnimals(Menagerie x) 
 
{ 
 
    var animals = x.getAnimals() 
 
    foreach (var animal in animals) 
 
    { 
 
     if (animal.Name == "cat") 
 
     { 
 
      FeedTheCat(); 
 
     } else if (animal.Name == "dog") 
 
     { 
 
      feedTheDog(); 
 
     } else if (animal.Name == "bees") 
 
     { 
 
      PutOnBeeSuit(); 
 
      foreach(bee in bees) FeedAnimals(new Menagerie() {bee}); 
 
     } 
 
     else 
 
     { 
 
      CallAMeeting(); 
 
      FeedAnimals(new Menagerie() {employees}); 
 
     } 
 
    } 
 
}

(これはところで、すべての擬似コードである)

「動物」の各タイプがどのように「フィードされているか」を確認できるようになりました。しかし、を与える行為はと異なる可能性があります。これは、多形性が作用するところです。データを使って何をすべきかについての意思決定から、あなたが適用できる「振る舞い」を持つ「タイプ」の作成に移ります。

この場合、一般的な「タイプ」は「動物」で、行動は「フィード」です。ポリモーフィズムを使用すると、特定のタイプに一般的なタイプと区別一部です:

class Animal { 
 
    public function Feed() {} 
 
} 
 

 
class Cat inheritsfrom Animal { 
 
    public function Feed() {} 
 
} 
 

 
class Bee inheritsfrom Animal { 
 
    public function Feed() {} 
 
} 
 

 
class Dog inheritsfrom Animal { 
 
    public function Feed() {} 
 
} 
 

 
class BeeHive { 
 
    list of Bee bees 
 
}

だから今、あなたのロジックのようなものに移行することができる:

public void FeedAnimals(List(of Animal) menagerie, string id = null) 
 
{ 
 
    foreach (var animal in menagerie) 
 
    { 
 
     if (animal is Cat) 
 
     { 
 
      animal.Feed(); 
 
     } else if (animal is Dog) 
 
     { 
 
      animal.Feed(); 
 
     } else if (animal is Bee) 
 
     { 
 
      PutOnBeeSuit(); 
 
      animal.Feed(); 
 
     } else if (animal is BeeHive) { 
 
      FeedAnimals animal.bees 
 
     } else 
 
     { 
 
      CallAMeeting(); 
 
      animal.feed(); 
 
     } 
 
    } 
 
}

どのように ".Feed"と呼んでいるのか見てみましょう。それはいいことだ。猫、犬、蜂は動物から継承しているので、実際には異なる「飼料」機能を持っており、言語はどのタイプが参照されているかに基づいてどちらを呼び出すのかを知っています。タイプは自動的に変数と関連付けられます(シーンの裏側)。

だから今、蜂の巣に1つのマイナーチェンジで、コードはに崩壊:

// new BeeHive class: 
 
class BeeHive inheritsfrom Animal{ 
 
    list of Bee bees 
 
    public function Feed() { 
 
    foreach(bee in bees) bee.Feed() 
 
    } 
 
} 
 

 
// new, collapsed code 
 
public void FeedAnimals(List(of Animal) menagerie, string id = null) { 
 
    foreach(var animal in menagerie) { 
 
    if (animal is Animal) { 
 
     CallAMeeting() 
 
    } 
 
    animal.Feed() 
 
    } 
 
}

私は、これは多型の実施を通じて思考のプロセスを明確アップに役立ちます願っています。

は、これはすべての擬似コードで、忘れてはいけない、とのコードに誤りがあります。概念を表現するのはここです。実行する(またはコンパイルする)のではありません。

+0

"FeedAnimals"の最初のパラメータを "Menagerie x"から "List of Animal" menagerieに変更しました。 "XElement xml"パラメータを変更する必要があることを説明できますか? – Limbo

+0

私はクラスとリストの文脈の違いを示すためにその変更を行いました。私のコードはすべて指導であったので、決して解決策としてはならない。データベースの思考からクラスベースの思考に移行することを考えるのに役立つだけです。私はそれをより明確にするために変数名を編集します。このパターンについて – theGleep

0

私はあなたがStrategyパターンと条件ロジックを置き換えるような状況を解決するために提案します。

検索 Martin Fowler氏の著書「戦略と条件ロジックを置き換え」とジョシュアKerievskyで"Refactoring to Patterns: Simplification"を読む

UML: uml

関連する問題