The Artima Developer Community
Sponsored Link •

Design Forum
Best design solution

2 replies on 1 page. Most recent reply: Oct 16, 2002 5:24 AM by Enrico Dell'Aquila

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 2 replies on 1 page
Enrico Dell'Aquila

Posts: 2
Nickname: eda
Registered: Jun, 2002

Best design solution Posted: Jun 13, 2002 6:01 AM
Reply to this message Reply
Advertisement
Hello, I'm rececently getting into java and OOP, and after reading some articles on this website I started to write a little exercise to apply the concepts.

Basically I'm writing an 'Expression' object that holds operands and operators.

Since the object 'Expression' is itself an operand, it is possible to pass it as an operand
to another espression.
In this way it is possible to simulate the behaviour of the various nested
sub-expression within the parenthesis that appear in a written-on-paper expression...


first of all, here are the classes I defined (the question is at the end):


1) two abstract classes for the two kinds of object that my Expression object will handle:
------------------------------------------------------------------------------- --------
abstract class Operand {
   public abstract void write();
} 
abstract class Operator {
   public abstract void write();
} 



2) 4 instances of the operators "sum, difference, multiply and division)
--------------------------------------------------------------------

(other to come, but for learning purpose it's enough)
class Odivide extends Operator {
    private final static String symbol  ="/";
    public void write() {
        System.out.print(symbol);
    }
}
class Omultiply extends Operator {
    private final static String symbol  ="*";
    public void write() {
       System.out.print(symbol);
    }
}
class Osubtract extends Operator {
    private final static String symbol = "-";
    public void write() {
        System.out.print(symbol);
    }
}
class Osum extends Operator {
    private final static String symbol  ="+";
    public void write() {
        System.out.print(symbol);
    }
}



3) instances of operands: an integer , a float and a string (4 chars).
----------------------------------------------------------------------
class Integer4 extends Operand {
    private Integer val;
    public Integer4(Integer i) {
       val = i;
    }
    public void write() {
        System.out.print(val.intValue());
    }
}
class Float4 extends Operand {
    private Float val;
    public Float4(Float f) {
       val = f;
    }
    public void write() {
        System.out.print(val.floatValue());
    }
}
class String4 extends Operand {
    private String val;
    public String4(String s) {
       val = s.concat("....").substring(0,4);
    }
    public void write() {
        System.out.print("'");
        System.out.print(val);
        System.out.print("'");
    }
}

4) the expression object (the real focus!)
-----------------------------------------

NOTE: it's an operand itself!!
class Expression extends Operand {
 
   Operand  op1;
   Operand  op2;
   Operator ope;
 
    public Expression( Operand o1, Operand o2, Operator op) {
       op1 = o1;
       op2 = o2;
       ope = op;
    }
    public void write() {
        System.out.print("(");
        op1.write();
        ope.write();
        op2.write();
        System.out.print(")");
    }
    public void writeWithoutParenthesis() {
        op1.write();
        ope.write();
        op2.write();
    }
 
    // -- just a placeholder , not used
    public Number calculate() {
        return new Integer(1);
    }
}


5) the main program object. Just for testing.

public class parsemath {
 
   public static void main (String[] args) {
 
      /*
       *  espr.      (((3+2) * (4+5))/(4.2/(5-3)))
       *                ---     ---         ---
       *                 A       B           C
       *                -----------    --------
       *                     D             E
       *              ---------------------------
       *                          F
       */
 
      // A
      Operand  op32_1		  = new Integer4( new Integer(3));
      Operand  op32_2  = new Integer4( new Integer(2));
      Operator ope32_1 = new Osum();
      Expression e32   = new Expression( op32_1, op32_2, ope32_1);
 
      // B
      Operand  op45_1  = new Integer4( new Integer(4));
      Operand  op45_2  = new Integer4( new Integer(5));
      Operator ope45_1 = new Osum();
      Expression e45   = new Expression(op45_1, op45_2, ope45_1);
 
      // C
      Operand  op53_1  = new Integer4( new Integer(5));
      Operand  op53_2  = new Integer4( new Integer(3));
      Operator ope53_1 = new Osubtract();
      Expression e53   = new Expression( op53_1, op53_2, ope53_1);
 
      // D
      Operator ope3245 = new Omultiply();
      Expression e3245 = new Expression( e32, e45, ope3245);
 
      // E
      Operand  op4_1  = new Float4( new Float(4.2));
      Operator ope453 = new Odivide();
      Expression e453 = new Expression( op4_1, e53, ope453);
 
 
      Operator opeTot = new Odivide();
      Expression eTot = new Expression( e3245, e453,opeTot);
 
 
      System.out.println("expression with numbers");
      eTot.writeWithoutParenthesis();
      System.out.println();
 
      /*
       *  espr.      "Hell" + "o wo" + "rld!"
       *              ----     ----     ----
       *               A        B        C
       *                ----------- 
       *                     D      
       *              ----------------------
       *                       E
       */
 
 
      // A
      Operand  opA  = new String4("Helloooo");
      // B
      Operand  opB  = new String4("o world");
      // C
      Operand  opC  = new String4("rld!");
 
      // D
      Operator opAB = new Osum();
      Expression eAB = new Expression( opA, opB, opAB);
 
      // E
      Operator opABC = new Osum();
      Expression eABC = new Expression( eAB, opC, opABC);
 
      System.out.println("espression with strings");
      eABC.writeWithoutParenthesis();
      System.out.println();
 
	System.out.println("OK.");
   }
}



If you compile and run all the classes, you can have an output of the
main expression with all the correctly nested parenthess.
(the string expression is here just to evidentiate that you can define
many different operands, not necessarily numeric. For the same reason,
you could image different kinds of operators, not necessarily arithmetic)

This is possible due to the 'write()' method available in all the operand-type and operator-type classes.

But what if I vanted a similar behaviour that instead of printing the expression calculates it?

I imagine a method 'calculate()' that, called for each sub-expression, do all the calculation
returning a value.

Obviously somewhere there has to be written some code to manage the different types of values
carried by the 'operands'
It is not the same thing to multiply two integers or an integer and a float... and how has to be treatd
a multiplication between an integer and a String? Is it impossible? Can return a string repeated n times?



And here is the main question:
What is the best design solution to achieve the calculation without having to reply code
in all the various classes?



I thought about a 'calculator' object that receives operands and operators, with
all the if-then-else instructions needed to manage the different object types.
As a new kind of operand arises, it's the calculator that has to be modified
to manage it, or to throw an 'UnknownOperand' or 'UnknownOperator' exception...


is this the right way to procede?
is there a better design implementation?
can we in some way put and manage some "intelligence" in the operator objects, so
data conversion and calculation is made easier?

Since this is a thing to understand OO design, i need design suggestion more than
a ready-to-go solution (well, if you have it, I'won't throw it away! :) )


I hope not to have been boring with this large post. Sorry if my english is confusing.

thanks in advance for anyone that will Answer

Enrico


Grant Sayer

Posts: 2
Nickname: gsayer
Registered: Oct, 2002

Re: Best design solution Posted: Oct 15, 2002 6:29 PM
Reply to this message Reply
One option is to use the Visitor pattern to walk the expression tree and at each operator take the operands and perform the appropriate action.

A good example is supplied with the JavaCC package which builds a parse tree given a grammar. You can nominate that you want the Visitor interface generated and then just implement the appropriate actions.

Enrico Dell'Aquila

Posts: 2
Nickname: eda
Registered: Jun, 2002

Re: Best design solution Posted: Oct 16, 2002 5:24 AM
Reply to this message Reply
thanks for the reply, I was not hoping someone answered anymore! :)

OK, I'm looking at the Visitor pattern on some books, and I start to figure out how to solve this problem...

but, what is JavaCC package?
Could you give me some links to visit?

thanks
Enrico

Flat View: This topic has 2 replies on 1 page
Topic: Deciding whether to use primitives or Objects Previous Topic   Next Topic Topic: about UML book

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use