1

I've recently had a real world use for the Strategy pattern. I find myself with hammer/nail syndrome where this pattern is my hammer and everything else is a nail. For kicks, I decided to try implementing FizzBuzz via the strategy pattern. Now, I know this is complete over kill. I've seen various Enterprise implementations of it, but this is my own implementation.

To my surprise and delight, this exercise turned up an interesting question: is there a standard or another pattern that works in conjunction with strategies to help you select which one to use? In my FizzBuzzStrategySelector class below, I put this logic in the Format function.

Obviously this implementation is not practical...but it might be if these Format methods actually had some real world logic to break down.

My basic question here is this: am I using the Strategy pattern correctly here?

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";;
    }
}
4

2 回答 2

2

由于(如您所知)策略模式对于这个问题来说太过分了,很难说什么是“好”或“坏”的设计。但是,我的直觉是将策略选择逻辑移到策略本身中,如下所示:

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

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

就可组合性而言,这可能会好一些,但您仍然需要确保您有一个IOutputFormatters 按正确顺序排列的列表。有了这么小的问题,你可以侥幸逃脱。对于更大的问题,您需要考虑并自己决定。

于 2013-03-22T19:48:36.547 回答
0

不同的输出格式化程序是策略模式的一部分。通常会有一个需要格式化程序的对象。然后你可以调用格式化程序。

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");

如何设置格式化程序,或者设置哪个格式化程序可能是另一个对象的责任。

于 2013-03-22T19:54:00.627 回答