Skip to content

fizz buzz

Mahmoud Ben Hassine edited this page Apr 9, 2018 · 7 revisions

This tutorial implements the FizzBuzz application with Easy Rules. FizzBuzz is a simple application that requires to count from 1 to 100 and:

  • print "fizz" if the number is multiple of 5
  • print "buzz" if the number is multiple of 7
  • print "fizzbuzz" if the number is multiple of 5 and 7
  • print the number itself otherwise

Here is a FizzBuzz example from Java Examples in a Nutshell book :

public class FizzBuzz {
  public static void main(String[] args) {
    for(int i = 1; i <= 100; i++) {
      if (((i % 5) == 0) && ((i % 7) == 0))
        System.out.print("fizzbuzz");
      else if ((i % 5) == 0) System.out.print("fizz");
      else if ((i % 7) == 0) System.out.print("buzz");
      else System.out.print(i);
      System.out.println();
    }
    System.out.println();
  }
}

We will write one rule for each requirement:

@Rule
public class FizzRule {

    @Condition
    public boolean isFizz(@Fact("number") Integer number) {
        return number % 5 == 0;
    }

    @Action
    public void printFizz() {
        System.out.print("fizz");
    }

    @Priority
    public int getPriority() {
        return 1;
    }
}
@Rule
public class BuzzRule {

    @Condition
    public boolean isBuzz(@Fact("number") Integer number) {
        return number % 7 == 0;
    }

    @Action
    public void printBuzz() {
        System.out.print("buzz");
    }

    @Priority
    public int getPriority() {
        return 2;
    }
}
public class FizzBuzzRule extends UnitRuleGroup {

    public FizzBuzzRule(Object... rules) {
        for (Object rule : rules) {
            addRule(rule);
        }
    }

    @Override
    public int getPriority() {
        return 0;
    }
}
@Rule
public class NonFizzBuzzRule {

    @Condition
    public boolean isNotFizzNorBuzz(@Fact("number") Integer number) {
        // can return true, because this is the latest rule to trigger according to assigned priorities
        // and in which case, the number is not fizz nor buzz
        return number % 5 != 0 || number % 7 != 0;
    }

    @Action
    public void printInput(@Fact("number") Integer number) {
        System.out.print(number);
    }

    @Priority
    public int getPriority() {
        return 3;
    }
}

Here are some explanations of these rules:

  • FizzRule and BuzzRule are straightforward, they check if the input is fizz or buzz and print the result
  • FizzBuzzRule is composite rule. We will create it with two composing rules: FizzRule and BuzzRule. The choice of the base class as UnitRuleGroup is important: Either both rules are satisfied and applied or nothing is applied.
  • NonFizzBuzzRule is for numbers that are not fizz nor buzz.

Note that we've set priorities so that rules are fired in the same order as the example from Java Examples in a Nutshell.

Then, we have to register these rules in a rules set and fire them using a rules engine:

public class FizzBuzzWithEasyRules {
    public static void main(String[] args) {
        // create a rules engine
        RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
        RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);

        // create rules
        Rules rules = new Rules();
        rules.register(new FizzRule());
        rules.register(new BuzzRule());
        rules.register(new FizzBuzzRule(new FizzRule(), new BuzzRule()));
        rules.register(new NonFizzBuzzRule());

        // fire rules
        Facts facts = new Facts();
        for (int i = 1; i <= 100; i++) {
            facts.put("number", i);
            fizzBuzzEngine.fire(rules, facts);
            System.out.println();
        }
    }
}

Note that we have set the skipOnFirstAppliedRule parameter to skip subsequent rules whenever a rule is applied.

To run this tutorial, you can follow these instructions:

$ git clone https://github.com/j-easy/easy-rules.git
$ cd easy-rules
$ mvn install
$ cd easy-rules-tutorials
$ mvn exec:java -P runFizzBuzzTutorial

You should get the following output:

1
2
3
4
fizz
6
buzz
8
9
fizz
11
12
13
buzz
fizz
16
17
18
19
fizz
buzz
22
23
24
fizz
26
27
buzz
29
fizz
31
32
33
34
fizzbuzz
36
37
38
39
fizz
41
buzz
43
44
fizz
46
47
48
buzz
fizz
51
52
53
54
fizz
buzz
57
58
59
fizz
61
62
buzz
64
fizz
66
67
68
69
fizzbuzz
71
72
73
74
fizz
76
buzz
78
79
fizz
81
82
83
buzz
fizz
86
87
88
89
fizz
buzz
92
93
94
fizz
96
97
buzz
99
fizz

Conclusion

In this tutorial, you have seen how to create rules, compose them and fire them in a particular order.

Easy Rules implementation of FizzBuzz my appear an overkill compared to the naive solution. This is true! Don't use Easy Rules to implement FizzBuzz application. We have used it here for demonstration purpose.

But when you start to have dozen of business rules, a naive solution with multiple nested if/then/else statements will quickly become hard to read, understand, test and maintain. With Easy Rules, you can design rules to do one thing (and do it well), that are easy to read, understand, unit test and compose.