HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Even more extensible and testable BuzzFizz

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
extensibletestablemoreandevenbuzzfizz

Problem

Inspired by Extensible and testable FizzBuzz I have decided to write my own implementation, partially based on my own answer and on the other answers.

First a warning to all of you: Never make such complicated code for such simple jobs!

Now the basic requirements of the code:

  • Should be capable of solving the FizzBuzz problem.



  • Should be capable of solving the FizzBuzz problem in a generic way, with any number of divisors and FizzBuzz-values.



  • Should be able to count in a generic way, we see all original FizzBuzz statements where people only count over int. But that is not enough for us! With this solution we can count over any Number that is comparable. I'm aware of the performance hits of boxed int/long, but with Java Value Types and Generics over Value Types (including primitives) that should be a problem of the past in the future.



Then now the code will follow.

FizzBuzz

```
/**
* Provides methods to convert numbers to their FizzBuzz-values given a set of rules.
*
* The FizzBuzz-value is a String obtained by applying a set of FizzBuzz-rules to a number.
* An example of a FizzBuzz-rule is that a number that is divisible by a 3, must result in Fizz.
*
* If multiple FizzBuzz-values are obtained by applying multiple FizzBuzz-rules, then they will be joined together using an ordering and a delimiter, both the ordering and delimiter are configurable via the provided builder, respectively by providing a Comparator and providing a String.
* An example of this is that in the classical FizzBuzz, the number 15 produces both Fizz and Buzz, with the default ordering and delimiter this will result in a FizzBuzz-value of FizzBuzz.
*
* This implementation only supports FizzBuzz-rules using divisibility.
*
* @author Frank van Heeswijk
* @param The number used to count.
*/
public class FizzBuzz> {
/** The sorted set of fizzers, to be used to calculate the FizzBuzz-value for every number. */
private final SortedSet> fizzBuzzRules;

/**

Solution

Hm, how do I put this nicely: you have overengineered an exercise that's designed to serve as a basic sanity check to weed out talentless job candidates pretending as programmers. Aaaaaaaah! ;-) // kidding!

I understand your pain about fizz-buzz implementations that only work with int values; however, generics is not a great way to do this. The problem definition only makes sense with integers, which limits the possible Java types to:

  • int / Integer



  • long / Long



  • BigInteger



Since these types are too similar,
this is not a typical pattern for using generics,
in fact using generics for this is really awkward.

A better solution would be to use BigInteger internally,
and provide overloaded methods for int and long,
which will all convert their parameters to the largest supported type (BigInteger).

This will have the following advantages:

  • The fizz-buzz logic can remain encapsulated: no need to force users to pass in the divisible predicate. The duplicated logic in all unit tests and every time you use the class will go away.



  • The fizz-buzz logic can remain encapsulated: a fizzbuzzer is of not much use if you have to tell it how to fizzbuzz!



  • The code will become a lot simpler



Another thing, the rangeFrom doesn't belong to FizzBuzz class,
as it adds an additional responsibility.
It's a bit like feature creep.
It seems convenient to provide this method,
but it weakens the API.
It would be better to move this logic to another class,
for example FizzBuzzStream.fromRange(start, end),
and stick to the single responsibility principle.

Context

StackExchange Code Review Q#74631, answer score: 10

Revisions (0)

No revisions yet.