用polimorphism替换条件如何

时间:2017-10-19 14:07:17

标签: c# design-patterns refactoring

我想用polimorphism替换以下递归函数中的if语句。

我读了很多关于它的信息,看了几个youtube视频,但仍然看不到在我的代码上实际执行此操作的方式(为了这篇文章的目的而简化了)

是什么让这个任务对我来说更加困难的是在函数的开头和递归调用中存在一个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();
}

4 个答案:

答案 0 :(得分:4)

如果你想使用具有代码之美的设计模式,那么我建议你使用多态,策略模式和模式搜索。

它将提供代码增强和可重用性的优势。

下面是代码示例:

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)

对于这种情况,多态性通过&#34;类型&#34;的概念来理解。和&#34;行为&#34;。这三个名字&#34;表示三种不同的类型 - 但你也有一个&#34; else&#34;,所以有四种类型可供使用。

(问题 - 您是否打算将if s设为完整的if / else链?在此代码中,{&#34; name1&#34;和&#34;执行else name2&#34;。我的答案取决于完整的if / else链......)

为了让它更容易理解,请考虑以下代码:

&#13;
&#13;
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});
        }
    }
}
&#13;
&#13;
&#13;

(这是所有伪代码,顺便说一下)

你现在可以看到每个动物&#34;类型正在&#34;喂养&#34;。但喂养的行为可能不同。这就是多态性发挥作用的地方 - 你将思考从决定应该对数据做什么到创建&#34;类型&#34;有&#34;行为&#34;你可以申请。

在这种情况下,一般&#34;类型&#34;是&#34;动物&#34;并且行为是&#34;饲料&#34;。多态性是您将一般类型区分为特定类型的部分:

&#13;
&#13;
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
}
&#13;
&#13;
&#13;

所以现在你的逻辑可以转变为:

&#13;
&#13;
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();
        }
    }
}
&#13;
&#13;
&#13;

看看你最终是如何打电话的,#34; .Feed&#34;每时每刻?这是一件好事。由于猫,狗,蜜蜂继承自动物,它们实际上有一个不同的&#34;饲料&#34;函数,语言根据引用的类型知道调用哪一个。并且类型自动与变量相关联(在幕后)。

现在,只需对BeeHive进行一次小改动,代码就会崩溃:

&#13;
&#13;
// 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()
  }
}
&#13;
&#13;
&#13;

我希望这有助于通过多态实现来清理思维过程。

别忘了,这是所有伪代码,代码中有ARE错误。它在这里表达概念,它不在这里运行(甚至编译)。

答案 2 :(得分:0)

多态性基于类型。您可以根据对象的类型(具有公共基类型)执行不同的函数(在您的情况下是if块中的语句)。

在您的情况下,您希望根据字符串执行不同的操作。因此,您要么从字符串创建类型并使用多态,要么使用映射(在C#中称为Dictionary)从字符串映射到函数(例如lambda表达式或C#中的Action)。根据不同功能的复杂程度和“nameN”的实际含义,选择其中一个。

在一种情况下,递归函数将是基础对象的一部分,或者在另一种情况下必须从lambda调用。

答案 3 :(得分:0)

我建议你用策略模式替换条件逻辑来解决这种情况。

搜索&#34;用策略替换条件逻辑&#34; 一本Martin Fowler的书,并阅读Joshua Kerievsky撰写的"Refactoring to Patterns: Simplification"

UML:   uml