patternjavaModerate
Even more extensible and testable BuzzFizz
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:
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;
/**
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 anyNumberthat 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
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
and provide overloaded methods for
which will all convert their parameters to the largest supported type (
This will have the following advantages:
Another thing, the
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
and stick to the single responsibility principle.
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.