TWiki . Doc . VisitorPatternMultiMethodExample

The first part of each example gives the existing datatypes and operations; the second part shows how we could add a datatype and how we could add an operation.

There are partial approaches - the Functional approach, easy to add an operation; the OO approach (Composite Pattern), easy to add a datatype - and approaches that allow extension of both datatypes and operations, the Visitor Pattern and Extensible Visitor Pattern.

Here's the multimethod and open class approach to extending software without modification.


/* Please try the NoviceExamples before the MultiMethodExamples
To compile:
   nicec --sourcepath .. -a multimethod.jar multimethod
To run:
   java -jar multimethod.jar
*/


// Multimethods: Types and Operations
//-----------------------------------

abstract class Shape {
   boolean containsPoint(Point p);
}

class Square extends Shape { 
   double side; 

   containsPoint(p) {
      let d = side/2;
      return 
         (p.x >= -d && p.x < d) && 
         (p.y >= -d && p.y < d);
   }
}

class Circle extends Shape { 
   double radius; 

   // just test the bounding box
   containsPoint(p) {      
      return 
         (p.x >= -radius && p.x < radius) && 
         (p.y >= -radius && p.y < radius);
   }
}

class Translated extends Shape { 
   Point d; 
   Shape shape; 

   containsPoint(p){
      let p' = 
         new Point(
            x: p.x - d.x,
            y: p.y - d.y );
 
      return shape.containsPoint(p');
   }
}

class Point { double x; double y; }



/*
   =================================================
   Can we add a type and operation without modifying 
   the original code?
   ================================================= 
*/


// Multimethods: Adding Type Variants
//-----------------------------------

class Union extends Shape {
   Shape shape1; 
   Shape shape2; 

   containsPoint(Point p) =
      shape1.containsPoint(p) || shape2.containsPoint(p);
}



// Multimethods: Adding Operations
//--------------------------------

Shape shrink(Shape s, double toPercent);

shrink(Square s, toPercent) = 
   new Square(side: (s.side*toPercent)/100);
   
shrink(Circle s, toPercent) = 
   new Circle(radius: (s.radius*toPercent)/100);

shrink(Translated s, toPercent) = 
   new Translated(d: s.d, shape: s.shape.shrink(toPercent)); 
   
shrink(Union s, toPercent) =
   new Union(
      shape1: s.shape1.shrink(toPercent),
      shape2: s.shape2.shrink(toPercent)   
   );  



// Multimethods: Testing
//----------------------

void main(String[] args){
   let s = new Square(side: 4);
   let c = new Circle(radius: 2);

   let t = 
      new Translated(
         d: new Point(x: 1.5, y: 0),  
         shape: c 
         );

   let p = new Point(x: 3, y: 0);

   println("square contains point " + s.containsPoint(p));
   println("circle contains point " + c.containsPoint(p));
   println("translated contains point " + t.containsPoint(p));


   let t' = t.shrink(toPercent: 50);
   println(
      "shrunk translated contains point " + 
         t'.containsPoint(p));
                            
   let u = new Union(shape1: s, shape2: t);
   println("union contains point " +  u.containsPoint(p));            
}



/* Notes 
See the detailed discussion in
"Synthesizing Object-Oriented and Functional Design to Promote Re-use"
Section 7 p110
http://citeseer.nj.nec.com/krishnamurthi98synthesizing.html


square contains point false
circle contains point false
translated contains point true
shrunk translated contains point false
union contains point true

*/
-- IsaacGouy - 06 Feb 2004

----- Revision r1.7 - 04 Apr 2005 - 10:57 GMT - TWikiGuest
Copyright © 1999-2003 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback.