// A simple Demeter/Java program for computing averages // traversal function // unfortunately we have to commit to specific visitors and // their types. But the benefit is that we can use the calling // mechanism of Java to attach context objects to calls. Container { traversal allWeights( CountingVisitor cV, SummingVisitor sV, AverageVisitor aV) { to Weight;} // it would be nicer if we could write: // traversal allWeights( // AverageVisitor aV) { // to Weight;} // assuming aV contains a cV and a sV. (@ // traverse while counting and summing float statistics() throws Exception { // adaptive specification of objects using parsing CountingVisitor cV = CountingVisitor.parse("0"); SummingVisitor sV = SummingVisitor.parse("0"); AverageVisitor aV = new AverageVisitor(cV,sV,new Float(0.0)); this.allWeights(cV,sV,aV); // better this.allWeights(aV); return aV.get_current().floatValue(); } @) } SummingVisitor { before Weight (@ System.out.println("sum"); total = new Integer(total.intValue() + host.get_i().intValue()); @) } CountingVisitor { before Weight (@ System.out.println("count"); total = new Integer(total.intValue() + 1); @) } AverageVisitor { (@ void update() { current = new Float( (float) this.get_sV().get_total().intValue()/ (float) this.get_cV().get_total().intValue()); System.out.println(current.floatValue() + " = partial result"); } ; @) before Weight (@ update(); @) } Main { (@ static public void main(String args[]) throws Exception { Runtime rt = Runtime.getRuntime(); rt.traceMethodCalls(true); Container a = Container.parse(System.in); float r = a.statistics(); System.out.println("done " + r); } @) }