2017-10-19 45 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