views:

386

answers:

9

Consider a rectangle with sides X and Y, and area Z such that Z=X*Y.

The rectangle has to be modeled into the cleanest OOD which will supply the following two services,

  1. Given side X and side Y, calculate area Z.
  2. Given side X and area Z, calculate side Y.

One possible design I was thinking on is,

A class Rectangle that have private invariant X and Y, public instance method Z = calcArea(), operating on X and Y, and public instance method Y = calcSide(Z), operating on X and on argument Z.

Good practice OOD tell us that Rectangle should have a constructor which initialize X and Y, with some valid values, both at once.

However, this solution implies that to calculate Y, given X and Z, one need to initialize the class constructor with Null value for Y. Initializing a invariant with Null is a dirty programming.

Is there any clean, one class, OOD solution?

+7  A: 

Perhaps create a static method (somewhat like a factory) which creates a Rectangle given a side and an area?

strager
A: 

Provide overloaded constructors and complete initialization within each constructor.

For the case where you provide X and Z, have a constructor that accepts both as arguments. Calculate and initialize Y within that constructor.

Eric J.
+3  A: 

The simplest solution is best OO design IMO.

To achieve JUST what you have asked; my offering is:

public static class Rectangle
{
    public static float Side(float side, float area)
    {
        return area / side;
    }

    public static float Area(float sideX, float sideY)
    {
        return sideX * sideY;
    }
}

Kindness,

Dan

Daniel Elliott
Yup, written in the best spirit of YAGNI.
Konrad Rudolph
+1  A: 

Rectangle object can have two factory methods to provide X and Y and X and Area.

public static Rectangle CreateRectangleWithXAndY(int? x,int? y)

public static Rectangle CreateRectangleWithXAndArea(int? x,int? area)

Or there can be a RectangleInfo class to provide info to a single constructor.

public Rectangle(RectangleInfo rectInfo)

I prefer nullable integer so that I can check to see what information is provided later. Calculation can be provided as read only properties.

public int Area
{
get
{
if(area==null)
area=_x*_y;
return area;
}
}

public int Y
{
get
{
if(_y==null)
_y=area/_x;
return _y;
}
}
Beatles1692
how would the compiler tell the constructors apart?
Daniel Elliott
you are right :) it can be two different factory methods or the can be a RectangleInfo class to provide info for a single constructor
Beatles1692
+6  A: 
public class Rectangle {
    private final double width;
    private final double height;

    private Rectangle (double width, double height) {
     this.width = width;
     this.height = height;
    }

    public double area() {
     return width * height;
    }

    public static Rectangle fromSides(double width, double height) {
     return new Rectangle(width, height);
    }

    public static Rectangle fromSideAndArea(double width, double area) {
     return new Rectangle(width, area / width);
    }
}
Carl Manaster
A: 

create a shape class and then extend it with your rectangle class.

This assuming you will have other shapes as well..

Jeff
A: 

Lazy load the value for the square's area.

public class Square {
  private int x, y, area = -1;

  public Square(int x, int y) {
    this.x = x;
    this.y = y;
  }


  public int CalcSide(int z) {
    return CalcArea()/z;
  }

  public int CalcArea() {
    return CalcAreaIfNotNull();        
  }

  private CalcAreaIfNotNull() {
    if (-1 == area) {
      area = x * y;
    }

    return area;
  }
}
JaredCacurak
+1  A: 

Why does it "[have] to be modeled into the cleanest OOD which will supply the following two services"? Modeling? OOD? Services? You're talking about a single multiplication and a single division, right?

Well, maybe if a crazy professor insisted, I'd write something like this:

(defclass rectangle ()
  ((x :initarg :x :initform nil :accessor x)
   (y :initarg :y :initform nil :accessor y)))

(defun area (rect)
  (* (x rect) (y rect)))

(defun make-rectangle-from-sides (x y)
  (make-instance 'rectangle :x x :y y))
(defun make-rectangle-from-side-and-area (x area)
  (make-instance 'rectangle :x x :y (/ area x)))

and then try to forget about how the class was sucking the life out of both programming and computer science.

Anybody insisting on "good practice OOD" while inventing problems that don't exist in Smalltalk or Lisp can, IMHO, stuff it.

Alec
+1  A: 

Thanks to you all for the helpful and insightful answers! This is not homework. Actually, this is a simplified representation meant to demonstrate real world financial problems I'm dealing with.

For example, Black&Sholts option pricing model derive the price out of a given 5 financial parameters. One of those 5 is volatility. There are times when you know the price and want to extract the implied volatility using the same computational core. Furthermore I have found the need for inverse calculation using the same computational core, to be a repetitive useful pattern. For example, you can extract bond price knowing the interest rate, but at times you need to extract the implied interest rate knowing the bond price. Often, those models run inside of an iterations loop. Insistence of using instance function, and not static function, has a performance virtue – by minimizing the function arguments, applicaion has less precondition to checks.

AA

A.A.