6.áThe counter Package

6.1.áSome Thoughts On Counting

The counting of elements is one thing which has to be done in nearly very program, of course not in the same scope and range. But what is counting actually? If you stand in front of a book shelf and you want to count the books on history and the one on programming, how will you count them? You will look at each book in the shelf and check if it is on history or programming. If not, you will look at the next book. If yes you will add one the 'counter' of history books or to the 'counter' of programming books. After checking the whole shelf, you will know how many books of both topics you own. Of course, you do this subconsciously.

Nethertheless this is the algorithm we use. If we would have to express the same thing as an piece of software we would identify three parts:

  1. The gizmos to count,
  2. the data structure which holds the results and
  3. the rules we use to identify the things we count.

The org.xshare.base.counters package contains the interfaces and the classes you need to splitt your code into the previous mentioned parts.

A counter from this package one can introduce oneself as an object which knows about some rules for other elements which can be passed to it and can increase an value if a rule matches one of these elements.

For example if someone would like to count all the red, green and yellow balls we owns, he could setup up one of the counters from this package and configure it with some rules. One rule to decide if a ball is red, another to decide if a ball is green and a thrid one to decide if a ball is yellow. Then he could pass all his balls to this counter and later check the number of red, green and yellow balls [2].

6.2.áAll Classes - A Short Overview

The org.xshare.base.counter package contains three basic interfaces: The DynamicCounter, the StaticCounter and the BaseCounter which is the root interface for both first. These three interfaces builds the whole counter hierarchy.

Besides these interfaces the package contains two default implementations for the DynamicCounter and the StaticCounter, which exactly behave as it is defined in their interfaces. Indeed these classes are package private, so you can't instanciate them directly. For this purpose the package contains the CounterFactory - a factory class.

6.3.áThe BaseCounter

This interface is the root interface for all counters - for the DynamicCounter as well as for the StaticCounter - and contains all the basic functionality.

The complete BaseCounter looks as the following:

      public interface BaseCounter {
        //
        // The methods to pass elements to a counter
        //
        void passThrough(Iterator pIterator)
        void passThrough(Object pVictim)

        //
        // All the methods to access the results.
        //
        int getResultFor(java.lang.Object pKey)
        Iterator getResultKeys()
        hasResultFor(java.lang.Object pKey)
      
        //
        // Last but not least a method to reset it.
        void reset()
      }
            
    

This interface provides three different groups of functionality: Methods to pass elements to a counter, to retrieve results and to reset a counter via reset().

Passing elements to a counter could be done via the passThrough() method, which is overloaded to accept every arbitrary element and iterations. All this elements will be passed to the internal stored 'rules' to see if at least one of them matches and a value has to be increased.

Please accept at the moment the existence of 'rules'. They will be explained when we discuss the StaticCounter and the DynamicCounter.

Important

If you write your own implementation of one of the interfaces in this package, you must ensure that the elements will be passed to all internal managed 'rules'.

Now we know how to feed a counter instance. Unfortunately this is only the half of it, we need a way to get the results of it too. Internally a counter associates every of its values with a key object, which can be used to obtain these values. The question there these keys come from is not interessting from the view of the BaseCounter and implementing classes can handle this differently. Later you will see, how it is realized for the StaticCounter and DynamicCounter. At the moment it is enough to know that there is a key/value pair for every result of the counter.

The methods in the second block give you access to the results. With the getResultFor(Object) you can access the result for a specific key. Is the key, you passed to this method unknown, you will get a NoSuchElementException[3] . If you are no sure that there is a associated value for this key, you can check it via hasResultFor(Object). To be sure that there is a associated value for this key, you can use the hasResultFor(Object) method.

If you would like to get all keys which a specific counter instance knows, you can use getResultsKeys() and iterate over all keys.

Imagine this class it the one we will use for our keys in the following example.

      final public class CounterKey {
        private String description = null;

        public CounterKey(String aDescription) {
          description = aDescription;
        }
        
        public String toString() {
          return "Result for " + description + ": ";
        }

        public boolean equals() {
          return ....;
        }
      }

    

Than we could write the following code to present the results to the end user:


      Iterator kIterator = counter.getResultKeys();

      while (kIterator.hasNext()) {
        Object o = i.next();
  
        System.out.println(o.toString() + counter.getResultFor(o));
      }

    

Finally there is the reset(), which brings the counter back to its orginal state before passing the first element to it.

6.4.áThe StaticCounter

In the previous chapter we started to use key objects to get results from a counter, but we didn't say a single word about the origin of these key objects and refered to the following chapters. Until know it is only known that a counter maintains an internal association of keys and values and that these values are increased if a 'rule' matches one of the elements passed to the counter instance.

The StaticCounter allows you to define rules and keys by yourself. For this purpose it introduces a new method: addRule(java.lang.Object pKey, UnaryPredicate pRule). Via this method you can specify the association between the key and the rule. To do that you must implement the 'rule' as UnaryPredicate, so that this predicate returns true if it matches one of the passed elements. The second object you need for this method is the key object for this predicate. When ever the predicate becomes true, the counter will increase the numerical value associated with the key.

Lets see how an example there we use a StaticCounter:

      
      public BaseCounter makeMeANiceCounterForAllMyBalls()
      {
         StaticCounter sc = CounterFactory.createStaticCounter();

         // As we said we need some predicates for our counter....
         UnaryPredicate redBalls = new UnaryPredicate() {
           public boolean exec(Object o) {
             return ((Ball)o).getColor() == BallColor.RED;
           }
         };

         UnaryPredicate greenBalls = new UnaryPredicate() {
           public boolean exec(Object o) {
             return ((Ball)o).getColor() == BallColor.GREEN;
           }
         };

         UnaryPredicate yellowBalls = new UnaryPredicate() {
           public boolean exec(Object o) {
             return ((Ball)o).getColor() == BallColor.YELLOW;
           }
         };

         // Lets configure the counter now....
        sc.addRule(new CounterKey("red"), redBalls);
        sc.addRule(new CounterKey("green"), greenBalls);
        sc.addRule(new CounterKey("yellow"), yellowBalls);

        return sc;
      }

    

What have we done? Since the standard implementation of the StaticCounter is quite alright for what we want to do, we obtained an counter instance from the factory in this package, created a predicate for red, one for green and one for yellow balls and put them together with a CounterKey into the counter itself. Since this type of counter maintains a 1-to-1 replationship for a key and a predicate/rule, a matching predicate will increase only the value of the associated key [4].

And what will happen, if you pass a 'black' ball to the counter? Nothing. We didn't specify a predicate for a black ball. If none of the predicates matches a element, no value will be increased.

Tip

To get the total number of elements passed to a counter is quite easy. Since every element is passed to every rule, you can simply do something like in the following example:

        StaticCounter sc = CounterFactory.createStaticCounter();
        sc.addRule(new CounterKey("TOTAL"), UnaryPredicate.ALWAYS_TRUE);
        ...

        System.out.println("Total number: " + 
                           sc.getResultFor(new CounterKey("TOTAL")));
        ...
      

6.5.áThe DynamicCounter

The counterpart of the previous counter type is the DynamicCounter, those association between a rule and a key is dynamic and not predefined - from the view of the counter.

As the StaticCounter it introduces a addRule(), but instead of an Object as key and an UnaryPredicate it takes an UnaryFunction as argument, which can act as a kind of factory for keys. This allows you to create the result key/value pairs one the fly.

The rewrite of the example method makeMeANiceCounterForAllMyBalls() with an DynamicCounter looks like this:

      public BaseCounter makeMeANiceCounterForAllMyBalls()
      {
         DynamicCounter dc = CounterFactory.createDynamicCounter();

         UnaryFunction uf = new UnaryFunction() {
           static CounterKey RED = new CounterKey("red");
           static CounterKey GREEN = new CounterKey("green");
           static CounterKey YELLOW = new CounterKey("yellow");

           public Object exec(Object o) {
            Ball c = (Ball)o;

             if (c.getColor() == BallColor.RED) 
               return RED;

             if (c.getColor() == BallColor.GREEN)
               return GREEN;

             if (c.getColor() == BallColor.YELLOW)
               return YELLOW;
   
             return null;
           }
         };

        dc.addRule(uf);

        return dc;
      }
    

At the frist glance the change doesn't look so big, but it is. If we look at the used UnaryFunction line by line, we will see that returns the key objects RED, GREEN and YELLOW only if it really gets an Ball which has one of these colors. So you can't be sure, that your counter has a result for one of this keys and a line like

      dc.getResultFor(new CounterKey("red"));
    

could result in a NoSuchElementException if no red ball was passed to the counter. In this example we have the disadvantages, that we can't be sure which results exist. But consider the following code:

      public BaseCounter makeMeANiceCounterForAllMyBalls()
      {
         DynamicCounter dc = CounterFactory.createDynamicCounter();

         UnaryFunction uf = new UnaryFunction() {
           public Object exec(Object o) {
             Ball c = (Ball)o;

             return new CounterKey(Ball.getColor().getName());
           }
         };

        dc.addRule(uf);

        return dc;
      }
    

In this example the UnaryFunction doesn't expect specific elements. It creates for every element a CounterKey and returns it. The counter picks up this key and checks if it is not null. If yes, the counter discards it. Otherwise it looks up a key/value pair with the same [5] key and increases the value of it. If the counter doesn't find a key/value it creates one and set the value to one.

Actually using an UnaryFunction allows you to count things, which you don't know, but you know how to formulate a rule, to identifies these things or to build groups of them. Maybe this is a little bit to abstract and an example will help you to understand it better [6] .

Supposing the following situation: You have to write a little programm to count all bottles with milk in the stock and to tell your boss, how many bottles from which cow you have.

To find out, which cow gave the milk for a certain bootle is easy - at least in our case, because we have a nice class MilkBottle with a method getCow(). So we know how we can find out the cow who gave the milk for a bottle. But nothing more. If we would like to have a counter where the key of key/value pair is the name of cow and the value the number of bottles full with milk of this cow, we can't take the StaticCounter since we need all the cow names before not to mention all the rules we have to create. Instead the DynamicCounter is exactly what we need. Simply we have to implement the UnaryFunction in the right way.

      ...

      /* Our own implementation of the UnaryFunction will act
       * as a factory for keys, indeed it does nothing more 
       * then to return the name of a given cow as name....
       */
      UnaryFunction rule = new UnaryFunction() {
        public Object exec(Object o) {
          return ((Cow)o).getName();
        }
      };

      
      DynamicCounter dc = CounterFactory.createDynamicCounter();

      dc.addRule(rule);

      .... Passing a lot of cows to it... a lot....

      Iterator kIterator = counter.getResultKeys();

      while (kIterator.hasNext()) {
        Object o = i.next();
  
        System.out.println("Cow " + o.toString() + " gave " +
                           counter.getResultFor(o) + " bottle(s)");
      }
    
    

6.6.áThe CounterFactory

Often, even if you divide you code into an interface and its implementing class, many "loc" writers [7] will programm against the implementing class. Sometimes it is ok if you do it with private members, but it is a kind of software terror if you force the clients of your class to do it too. To avoid this risk for the counter package, it contains a factory class so that no one has access to the implementing classes of both counters. For that the CounterFactory offers to methods: createStaticCounter() and createDynamicCounter(). They does exactly what the names suggest.

Besides this, the factory class offers methods to synchronize instances of these counters.



[2] Of course we are more serious and count money, shares, users and similar things in our projects.

[3] To choose the NoSuchElement for this was a mistake and will be changed later.

[4] This is the reason why the this type of counter is called StaticCounter. The association between a 'rule' and 'key' can't be changed. It is static...

[5] If two keys are the same or not is checked via equals(Object).

[6] If you know how to describe it better in English, please drop me a line.

[7] lines of code writers