Используйте шаблон посетителя, чтобы обработать другое, если

Интересно, есть ли способ справиться с простым условием с помощью шаблона посетителя или нет?

Например, если у нас есть приведенный ниже код, как мы можем применить к нему шаблон посетителя?

public class Elseif
{
    private int total;
    public int Condition(int x)
    {
        if(x==1)
        {
            total = 100;
        }
        else if(x==2)
        {
            total = 200;
        }
        return total;

    }
}

другими словами, как вы хотите написать перегрузку для интерфейса IVisitor?

public interface IVisitor
{
    int Visitor(int x);
}

3 ответа

Решение

Шаблон посетителя предназначен для различения различных типов, особенно если у вас есть объект (абстрактного) суперкласса, и вы хотите делать особые вещи в зависимости от конкретного типа. Это означает, что вы можете (и должны) использовать его вместо if-then-else с приведением тестов.

Шаблон посетителя не предназначен для различения ценностей.

Может быть, вы ищете шаблон цепочки ответственности?

Допустим, вы должны рассчитать бонус, и вы используете что-то вроде этого

public double GetBonusRate(int workingDays, int numberOfSales)
{
    if(numberOfSales > 20)
    {
      return 1.5;
    }

    if(workingDays >= 20 && numberOfSales > 10)
    {
      return 1.2;
    }

    if(numberOfSales > 5)
    {
      return 1.0;
    }

    if(workingDays > 10)
    {
      return 0.1;
    }

    return 0;
}

Вы ожидаете, что число условий будет расти, и вы понимаете, что добавление нового условия в неправильном месте вызовет ошибку.
Цепочка ответственности дает вам другой подход.

var chain = new PerfectBonusRate();
chain.RegisterNext(new GoodBonusRate())
    .RegisterNext(new StandartBonusRate())
    .RegisterNext(new LazyBonusRate())
    .RegisterNext(new NoBonusRate());

var bonusRate = chain.GetBonusRate(10, 20);

Реализация

abstract class ChainElement
{
    ChainElement _next;

    public ChainElement RegisterNext(ChainElement next)
    {
        _next = next;
        return next;
    }

    public double GetBonusRate(int workingDays, int numberOfSales)
    {
        if(IsMatched(workingDays, numberOfSales))
        {
            return GetBonusValue();
        }

        return _next.GetBonusRate(workingDays, numberOfSales);
    }

    protected abstract bool IsMatched(int workingDays, int numberOfSales);

    protected abstract int GetBonusValue();
}

class PerfectBonusRate : ChainElement
{
    protected override bool IsMatched(int workingDays, int numberOfSales)
    {
        return numberOfSales > 20;
    }

    protected override double GetBonusValue()
    {
        return 1.5;
    }
}

class GoodBonusRate : ChainElement
{
    protected override bool IsMatched(int workingDays, int numberOfSales)
    {
        return workingDays >= 20 && numberOfSales > 10;
    }

    protected override double GetBonusValue()
    {
        return 1.2;
    }
}

//and the same for StandartBonusRate, LazyBonusRate...

class NoBonusRate : ChainElement
{
    protected override bool IsMatched(int workingDays, int numberOfSales)
    {
        return true;
    }

    protected override double GetBonusValue()
    {
        return 0.0;
    }
}

Шаблоны, используемые для решения некоторых конкретных задач. Шаблон посетителя решает следующую проблему - добавление новых возможностей в (составную) структуру объектов без изменения этих объектов. Итак, позвольте мне перефразировать ваш вопрос - как я могу добавить новые возможности в структуру объектов, не имея структуры объектов и добавляемых возможностей. Это похоже на забивание гвоздя скрипкой.

Помните - сначала идет проблема. Затем идет образец, который решает эту проблему. Не наоборот.

ОБНОВЛЕНИЕ так, какая проблема у вас кода? Он не следует принципу разделения команд и запросов. Тот же метод выполняет действие (изменение итога) и возвращает итоговую сумму вызывающей стороне. Я разделил команду и запрос, чтобы сделать ваш код более понятным:

public int Total { get; set; }

public void DoSomething(int x)
{
    if(x == 1)
    {
        Total = 100;
        return;
    }

    if(x == 2)
    {
       Total = 200;
       return;
    }
}
Другие вопросы по тегам