Prev Next

Defining methods

Adding basic features/functionalities

The next step is to add the 'real' features to the class which manipulate the attributes. We do it in two stages. In this page, we define methods that necessitate working with attributes pertaining to a single object.

Let's state the features before implementing the methods.

  1. A method that can tell if the point is origin.

  2. A method that tells which quadrant the point belongs to.

  3. A method each that provides the projection of the point on x- and y-axes respectively.

  4. A method to perform scalar multiplication of the point.

1. Is the point origin?

This is a straight-forward method to implement. It does not need any argument and returns a boolean value: true or false. The method signature is given below.

  /** Return true if both x and y are 0s. Else return false. */

  public boolean isOrigin() {

    // Your code here

  }

Create a new test case to check the correct working of isOrigin().

  Point p = new Point(4,7); 
  System.out.println( p.isOrigin() ); // should print false

  Point q = new Point(); 
  System.out.println( q.isOrigin() ); // should print true

2. Which quadrant does the point belong to?

A point can belong to one of the four quadrants. Check the x and y values of 'this' object and return 1, 2, 3 or 4. If it is the origin then return 0. The method signature is given below.

  /** First check if the point is origin. If so, return 0.
      Else check x and y values and return the quadrant. 
      Reuse isOrigin() rather than check x and y again. */

  public int whichQuadrant() {

    // Your code here

  }

Implement test case(s) to check the correct working.

  Point p = new Point();
  System.out.println( p.whichQuadrant() ); // should print 0

  Point q = new Point(4,3);
  System.out.println( q.whichQuadrant() ); // should print 1

  q.setX(-8); // q is (-8,3) now
  System.out.println( q.whichQuadrant() ); // should print 2

  q.setY(q.getY() * -1);  // q is now (-8,-3)
  System.out.println( q.whichQuadrant() ); // should print 3

  q.setX(q.getX() / -2);  // q is (4,-3)
  System.out.println( q.whichQuadrant() ); // should print 4

3. Projection of a point on x-axis and y-axis

Projecting a point (x,y) on x-axis returns (x,0). One important thing to note is that you don't want to change 'this' point's coordinates. Instead you like to create a new Point object, copy the x-value, set y to 0 and return it.

    /** Instantiate a new Point object, assign x-value of this to 
        x-value of the new point, set y-value to 0 and return it. */

  public Point xProjection() {

    /* Either use the default constructor which sets x and y to 0
       and invoke setX() on the new Point instance OR use the other
       constructor to pass this.x and 0 as arguments. */

    // Your code here

  }

  public Point yProjection() {

    // Your code here

  }

Again write test driver(s) to check the working.

4. Scalar multiplication of a point

Lets say you want to multiply the point by an integer (scalar). The method takes an argument c which is to be multiplied to x and y. Note that there are two ways to implement this.

Mutable implementation Non-mutable implementation
        public void scalarMultiply(int c) {
          x = c * x; 
          y = c * y;
        }
      
        public Point scalarMultiply(int c) {
          Point q = new Point(c.x, c*y);
          return q;
        }
      

The former is the mutable implementation wherein you change the attributes (in other words mutating the data) while the latter does not alter the attributes. Instead, it creates a new Point instance and does the necessary changes and returns it - similar to projection function.

Mutable implementation is more suited when you need to alter the object state often and you don't need the previous values. Non-mutable implementation makes a copy of the object and hence are suited when you need the previous values. However, non-mutable implementation tends to be slower since it involves creating a new object instance and the return operation.

The respective test driver code snippets are given below.

Testing mutable implementation Testing non-mutable implementation
        Point p = new Point(3,8);
        p.scalarMultiply(5);
        p.print();
      
        Point p = new Point(3,8);
        Point q = p.scalarMultiply(5);
        q.print();
      

Note that the following piece of code is a 'non-mutable' way to produce the 'mutable' effect.

   Point p = new Point(3,8);
   p = p.scalarMultiply(5);

However, this is not recommended, especially when the method is invoked very often, since it slows down the execution and creates numerous objects in the memory which needs to be garbage collected.

Based on the scenario/necessity a particular choice of implementation is adopted. A class is said to be immutable if all the methods are immutable (and the class cannot be extended). What is extension of a class? We will see later.

GOLDEN RULE TO FOLLOW: IMPLEMENT ONE METHOD FOR EACH FUNCTIONALITY
- Never overpack or mixup multiple functionalities in a single method.
- Reuse the methods whenever needed instead or re-implementing the code.