2017-10-19 64 views
1

我想用多態性代替下面的遞歸函數中的if語句。用多態性代替條件如何

我很多讀到它,看到幾個YouTube視頻,但仍然不能看到的實際上做它在我的代碼(這是簡化了這篇文章的目的)

什麼使得這一任務更加困難的路我是一個foreach statment的在函數的開頭存在和遞歸調用

感謝您的幫助

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

你能澄清你的意思嗎?用「多態性」來代替? – Evk

+0

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

+0

這個重構在這裏並不適合。如果你真的想要,你可以創建一堆類,但是在這種情況下它不會改進代碼。 – Evk

回答

3

如果你想使用設計模式與代碼的美女那麼我會建議你使用多態,策略模式和模式搜索。

它將提供代碼增強和可重用性的優勢。

下面的代碼示例:

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

這種模式唯一的一點是OperationContext約束器不斷增加,因爲新名稱被添加,但是非常接近我想要執行的操作。 – Limbo

+0

您可以將OperationContext構造器的添加操作移動到方法的字典操作中。然後您可以將該方法調用到構造函數中。 –

0

多態性是基於類型。你可以根據對象的類型(它有一個共同的基類型)執行不同的函數(在你的情況下是if塊中的語句)。

在你的情況下,你想基於一個字符串做不同的事情。因此,您可以從字符串創建一個類型,並使用多態性,或者使用映射(在C#中稱爲Dictionary)將字符串映射到函數(例如,lambda表達式或C#中的Action)。根據不同功能的複雜性和「nameN」的實際含義選擇一個或另一個。

遞歸函數在一種情況下是基礎對象的一部分,或者在另一種情況下必須從lambda中調用。

1

對於這種情況,通過「類型」和「行爲」的概念來理解多態性。三個「名稱」表示三種不同的類型 - 但您也有一個「其他」,所以有四種類型可以使用。

(問題 - 你打算if s是一個完整的if/else鏈嗎?在這段代碼中,else是爲「name1」和「name2」執行的,我的答案取決於完整的if/else鏈。 。)

爲了更容易一點理解,考慮下面的代碼:

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」?這是好事。由於貓,狗,蜜蜂從動物身上繼承,他們實際上有一個不同的「Feed」功能,並且該語言根據所引用的類型知道要調用哪一個。類型自動與變量關聯(幕後)。

所以,現在有一個小的改動蜂箱,代碼摺疊到:

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