Заменить условный на полиморфизм, как

2

Я хотел бы заменить операторы if в следующей рекурсивной функции с полиморфизмом.

я много читаю об этом, см. несколько видеороликов YouTube, но все же не могу видеть, как это делается на моем коде (что было упрощено для этой публикации)

то, что затрудняет эту задачу для меня, - это наличие предсказанной даты в начале функции и рекурсивный вызов

Спасибо за помощь

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
    Можете ли вы уточнить, что вы подразумеваете под заменой «с полиморфизмом»?
  • 0
Показать ещё 3 комментария
Теги:
design-patterns
refactoring

4 ответа

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
    единственное, что есть в этом шаблоне, это то, что Конструктор OperationContext продолжает расти по мере добавления новых имен, но довольно близок к тому, что я хочу сделать
  • 0
    Вы можете переместить добавление конструктора OperationContext в словарную операцию в метод. А затем вы можете вызвать этот метод в конструктор.
1

Для этой ситуации полиморфизм понимается через понятие "типы" и "поведение". Три "имени" указывают три разных типа, но у вас также есть "else", поэтому есть четыре типа для работы.

(Вопрос: вы предполагали, что if бы была полная цепочка 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"? Это хорошо. Поскольку Cat, Dog, Bee унаследованы от животных, у них фактически есть другая функция "Feed", и язык знает, какой из них вызывать, в зависимости от того, на какой тип ссылаются. И тип автоматически связан с переменной (за кулисами).

Итак, теперь с одним незначительным изменением на BeeHive код сворачивается в:

// 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»?
  • 0
    Нет. Я сделал это изменение, чтобы показать контекстную разницу между классом и списком. Весь мой код был инструкцией и не должен рассматриваться как какое-либо решение. Он просто поможет вам подумать о переходе от мышления на основе данных к мышлению на основе классов. Я отредактирую имена переменных, чтобы сделать это более понятным.
0

Полиморфизм основан на типах. Вы можете выполнять различные функции (в вашем случае инструкции в блоках if) в зависимости от типа объекта (который имеет общий базовый тип).

В вашем случае вы хотите делать разные вещи на основе строки. Таким образом, вы либо создаете тип из строки, и используете полиморфизм, либо используете карту (в С# под названием "Словарь") для отображения из строки в функцию (например, выражение лямбда или действие в С#). В зависимости от сложности различных функций и фактического значения "nameN" выберите тот или иной.

Функция рекурсии будет частью базового объекта в одном случае или должна быть вызвана из лямбда в другом случае.

0

Я предлагаю вам решить эту ситуацию, заменив условную логику на шаблон стратегии.

Поиск "Заменить условную логику со стратегией" в книге Мартина Фаулера и прочитать "Рефакторинг для шаблонов: упрощение" Джошуа Кериевского

uml: Изображение 174551

Ещё вопросы

Сообщество Overcoder
Наверх
Меню