Является ли это правильной реализацией паттерна Strategy с упражнением FizzBuzz?

Недавно у меня было реальное использование шаблона Strategy. У меня синдром молотка/гвоздя, когда этот узор — мой молоток, а все остальное — гвоздь. Ради интереса я решил попробовать реализовать FizzBuzz с помощью шаблона стратегии. Теперь я знаю, что это полное убийство. Я видел различные реализации Enterprise, но это моя собственная реализация.

К моему удивлению и радости, это упражнение выявило интересный вопрос: существует ли стандарт или другой шаблон, который работает в сочетании со стратегиями, чтобы помочь вам выбрать, какую из них использовать? В моем классе FizzBuzzStrategySelector ниже я поместил эту логику в функцию Format.

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

Мой основной вопрос здесь таков: правильно ли я использую здесь паттерн «Стратегия»?

class Program
{
    static void Main(string[] args)
    {
        FizzBuzzStrategySelector fizzBuzzFormatter = new FizzBuzzStrategySelector();

        for (int i = 1; i < 100; i++)
        {
            fizzBuzzFormatter.Format(i);
        }

        Console.ReadLine();
    }
}

public interface IOutputFormatter
{
    string FormatOutput(int value);
}

public class FizzBuzzStrategySelector
{
    public IOutputFormatter formatStrategy;

    public FizzBuzzStrategySelector() : this(new GeneralFormatter()) { }

    public FizzBuzzStrategySelector(IOutputFormatter fizzBuzzFormatStrategy) 
    {
        this.formatStrategy = fizzBuzzFormatStrategy;
    }

    public void Format(int value)
    {
        //THIS SEEMS LIKE A CODE SMELL. NOT SURE HOW TO WORK 
        //AROUND IT.
        if(value % 15 == 0)
            this.formatStrategy = new FizzBuzzFormatter();
        else if(value % 3 == 0 )
            this.formatStrategy = new FizzFormatter();
        else if(value % 5 == 0)
            this.formatStrategy = new BuzzFormatter();
        else
            this.formatStrategy = new GeneralFormatter();

        Console.WriteLine(this.formatStrategy.FormatOutput(value));
    }
}

public class GeneralFormatter : IOutputFormatter
{
    public string FormatOutput(int value)
    {
        return value.ToString();
    }
}

public class FizzBuzzFormatter : IOutputFormatter
{
    public string FormatOutput(int value)
    {
        return "FizzBuzz";
    }
}

public class BuzzFormatter : IOutputFormatter
{
    public string FormatOutput(int value)
    {
        return "Buzz";
    }
}

public class FizzFormatter : IOutputFormatter
{
    public string FormatOutput(int value)
    {
        return "Fizz";;
    }
}

person jason    schedule 22.03.2013    source источник


Ответы (2)


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

class Foo
{
   public IOutputFormatter Formatter {get;set;}
}

var foo = new Foo();
foo.Formatter = new GeneralFormatter();
Console.WriteLine(foo.formatter.FormatValue("one");

foo.Formatter = new FizzBuzzFormatter();
Console.WriteLine(foo.formatter.FormatValue("one");

За то, как установлен форматтер или какой форматтер установлен, может отвечать другой объект.

person Jason Meckley    schedule 22.03.2013
comment
Ну так это закодировано. В настоящее время конкретная стратегия задается в классе FizzBuzzStrategySelector. - person jason; 23.03.2013
comment
тогда пример путает проблему стратегии с шаблонами фабрики и реестра. - person Jason Meckley; 23.03.2013
comment
Спасибо! Я тогда посмотрю на них и постараюсь разобраться. - person jason; 23.03.2013
comment
вы обнаружите, что фабрика и объекты реестра идут рука об руку с шаблоном стратегии. Шаблоны очень хорошо работают вместе, но один не обязан использовать другой. - person Jason Meckley; 24.03.2013

Поскольку (как вы знаете) шаблон стратегии является излишним для решения этой проблемы, трудно сказать, что будет «хорошим» или «плохим» дизайном. Однако моей внутренней реакцией было бы перенести логику выбора стратегии в сами стратегии, например так:

class FizzBuzzFormatter : IOutputFormatter
{
    public bool Handles(int value) { return value.IsDivisibleBy(15); }

    public string Handle(int value) { return "FizzBuzz"; }
}

Это может быть немного лучше с точки зрения компоновки, но вам все равно нужно убедиться, что у вас есть список IOutputFormatters в правильном порядке. С такой маленькой проблемой можно обойтись чем угодно. При более крупной проблеме нужно подумать и решить для себя.

person default.kramer    schedule 22.03.2013