Как инкапсулировать логику в один метод

336
27 января 2017, 04:35

Я реализую задачу "Дилемма заключённого".

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

Я создал абстрактный класс для стратегии:

public abstract class StrategyBase
{
    public string StrategyName { get; set; }
    public abstract Action Init();
    public abstract Action Next(Action previousActionOfAnotherPrisoner);
}
public enum Action
{
    Tie = 0,
    Informer = 1
}

класс заключённого:

public class Prisoner 
{
    public string PrisonerName { get; private set; }
    public StrategyBase Strategy { get; private set; }
    public Action? LastAction { get; private set; }
    public int TotalYears { get; private set; }
    public Prisoner(string name, StrategyBase strategy)
    {
        if (strategy == null)
            throw new ArgumentNullException("strategy");
        PrisonerName = name;
        Strategy = strategy;
    }
    public void Do(Action? previousActionOfAnotherPrisoner)
    {
        if (previousActionOfAnotherPrisoner == null)
            LastAction = Strategy.Init();
        else
            LastAction = Strategy.Next(previousActionOfAnotherPrisoner.Value);
    }
    public void AddYears(ConvictionYears years)
    {
        TotalYears += (int)years;
    }
}

Далее класс Дилемма это всё вызывает:

public class Dilemma
{
    private Prisoner prisoner1;
    private Prisoner prisoner2;
    public Dilemma(Prisoner prisoner1, Prisoner prisoner2)
    {
        if (prisoner1 == null)
            throw new ArgumentNullException("prisoner1");
        if (prisoner2 == null)
            throw new ArgumentNullException("prisoner2");

        this.prisoner1 = prisoner1;
        this.prisoner2 = prisoner2;
    }
    public IterationInfo Iteration()
    {
        Action? previousAction1 = prisoner1.LastAction;
        Action? previousAction2 = prisoner2.LastAction;
        prisoner1.Do(previousAction2);
        prisoner2.Do(previousAction1);
        Utils.AddYears(prisoner1, prisoner2);
        return new IterationInfo(prisoner1.LastAction.Value, prisoner2.LastAction.Value, prisoner1.TotalYears, prisoner2.TotalYears);
    }
}

Это всё чудесно работает. Но мне не нравится один момент - начисление лет. Т.к. их начисление для каждого зависит от решения второго заключённого, я не могу эту логику засунуть в Do, а вынужден разнести по 2-м методам. и вызывать их из вызывающего класса Dilemma последовательно (в данном случае логика сколько лет дадут тому или другому инкапсулирована в Utils.AddYears()). Мне не нравится, что клиент должен "не забыть" вызвать AddYears. По сути, это всё должно быть в одном действии. Как такое правильно реализовать? В методе Do устанавливать временную переменную и городить логику проверок?

READ ALSO
Как правильно разобрать строку?

Как правильно разобрать строку?

Получаю строку: Иван 5 рублей 20 копеек(значение выделенное жирным всегда разное) Как разбить это всё в 3 переменные: name = Иван; rub = 5 рублей; kop = 20 копеек

301
Асинхронность в C#

Асинхронность в C#

Мне нужно реализовать асинхронную работу UI и алгоритма в своей программеЯ уже делал что-то подобное в прошлом, но тогда мой алгоритм ничего...

473
Несколько вопросов про Dapper

Несколько вопросов про Dapper

Поддерживает ли они подготовку запроса или каждый запрос компилируется по новой?

355
Переменная в C#

Переменная в C#

Учусь C#, читаю чужой код и возник вопрос, что обозначают {0} таким символом, это элемент массива? Вот весь кусок

324