Over Engineered Fizz Buzz with Objects and Patterns

I was having some fun with the FizzBuzz kata and wanted to share an object-oriented (OO) solution I was playing about with. I wanted to see what FizzBuzz would be like if a number range and each rule were objects. If you’ve done FizzBuzz before then I’m sure you’ve seen something along the lines of the following which is a typical procedural solution to the kata:

class FizzBuzz {
    String forNumber(int number) {
        if(number % 3 == 0 && number % 5 == 0) return "FizzBuzz";
        if(number % 3 == 0) return "Fizz";
        if(number % 5 == 0) return "Buzz";
        return String.valueOf(number);
    }
}

 

What I tried in my solution here https://github.com/Squaretechre/object-oriented-fizz-buzz was to use the chain-of-responsibility pattern to recreate the above but with a chain of Rule objects. Here are two rules, one for converting a number evenly divisible by 5 to the string “Buzz” and another rule that is the default case for the chain where no rule matched and we just return the number converted to a string:

public class BuzzRule implements Rule {
    private Rule nextRule;

    BuzzRule(Rule nextRule) {
        this.nextRule = nextRule;
    }

    @Override
    public String applyTo(int number) {
        return number % 5 == 0
                ? "Buzz"
                : nextRule.applyTo(number);
    }
}
public class NoMatchRule implements Rule {
    @Override
    public String applyTo(int number) {
        return String.valueOf(number);
    }
}

 

All of the individual rules are then built into a chain, and then using the composite pattern the chain is hidden behind the Rule interface so that the chain of rules can be treated as a single rule:

public class CompositeRule implements Rule {
    @Override
    public String applyTo(int number) {
        var noMatchRule = new NoMatchRule();
        var fizzWhenDivisibleByThreeRule = new FizzWhenDivisibleByThreeRule(noMatchRule);
        var fizzWhenContainsThreeRule = new FizzWhenNumberContainsThreeRule(fizzWhenDivisibleByThreeRule);
        var buzzRule = new BuzzRule(fizzWhenContainsThreeRule);
        var fizzBuzzRule = new FizzBuzzRule(buzzRule);

        return fizzBuzzRule.applyTo(number);
    }
}

 

 

Then there is a NumericRange object with a method called apply that takes a Rule which can be applied to each number in order to return a list of strings. This can then either accept a single rule or the composite rule:

class NumericRange {
    private List<Integer> range;

    NumericRange(List<Integer> range) {
        this.range = range;
    }

    NumericRange(int start, int end) {
        range = IntStream.range(start, end + 1)
                .boxed()
                .collect(Collectors.toList());
    }

    List<String> apply(Rule rule) {
        return range
                .stream()
                .map(rule::applyTo)
                .collect(Collectors.toList());
    }
}

 

Once I’d implemented the criteria on the Coding Dojo version of FizzBuzz I started looking at Jason Gorman’s Evil FizzBuzz exercise. Evil FizzBuzz is an exercise for team collaboration but I wanted to see how an OO solution that can be more easily decomposed would fit into the exercise. Evil FizzBuzz extends FizzBuzz with the following rules:

  • Any prime numbers are replaced with “Wizz”, or concatenated if already “Fizz” or “Buzz”, i.e. “FizzWizz”, “BuzzWizz”
  • Output as a comma-delimited string

And the rules for making FizzBuzz evil as a team exercise are:

  • Split the group up into 6 pairs (or threes, or ones, depending on how many people you’ve got)
  • Assign each part of FizzBuzz above (1-6) to a pair. They can only work on code for that part of the whole
  • Task them to work together – but only coding/TDD-ing their individual parts – to deliver a complete solution that produce the desired output

I thought the implications of an OO design were interesting from a team perspective. In the approach I took the two key design choices are that a range of numbers is an object and also each rule is an object. A team could decide amongst themselves the contract for a Rule, decide that these rules will be chained together and that a number range will then be passed these rules and apply them to itself. Then the number range can be wrapped in another object that converts its output to a comma separated string, for example:

class CommaSeparatedNumericRange {
    private NumericRange numericRange;

    CommaSeparatedNumericRange(NumericRange numericRange) {
        this.numericRange = numericRange;
    }

    String apply(Rule rule) {
        return String.join(", ", numericRange.apply(rule));
    }
}

This way each sub-team could focus on one part of the problem, either building rules, the number range or the conversion to CSV.

It was an interesting exercise and left me with a few thoughts about the pros and cons:

Pros:

  • Easier to add new rules into the chain
  • Rules can be tested in isolation
  • Rules can be reused or chained together in new ways
  • Easier to add the extra requirements in the Evil FizzBuzz exercise

Cons:

  • Using the Chain-of-Responsibility pattern can get a little unruly, larger chains are harder to reason about
  • Lots of classes / ceremony for not a lot of behaviour
    • For a small problem like this maybe a more procedural solution is actually clearer?

In summary I thought it was it fun to look at FizzBuzz from an OO perspective with little objects collaborating to achieve the same behaviour you can create using if statements. Whether this approach is what’s best for FizzBuzz, I don’t know, but there are some interesting implications when it comes to slicing the problem / the Evil FizzBuzz exercise.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment