Multiple Files to Make One Project - Start OOP#

Long code is unbearable to read and difficult to make work, except for the abstractions we use to organize it: methods and files (classes). You have already seen methods, used to name a chunk of code to enable reusing that code or, at least, breaking the code into smaller units. Files or classes are a higher level of abstraction and essential to an object-oriented structure for a program.

In true object-oriented programming, the main nouns in describing the problem become individual files or classes. Each class contains the complete essence of the noun, including variables to characterize the noun and actions that can be done to the noun.

Example of Square, Right Triangle, Circle Data Types#

Let’s consider the example of software for the flooring industry. A small part of this software may be to perform calculations of area or perimeter on various shapes that could be cut from the flooring material. We will take three example shapes: a square, a right triangle, and a circle. Each of these would have a calculation for area, albeit different formulas are used. Instead of writing the area as a complicated method in one file, a method that would need to determine whether we had a square, a right triangle, or a circle, we write a shortened version of the method in three files – one file for a square, one for a right triangle and one for a circle. Before we even start writing methods, we would need to determine what attributes are important or distinguishing for a square (e.g. length of one side), for a right triangle (e.g. base and height), and for a circle (e.g. radius). These attributes are placed into each file and are called instance (or class, if static) variables. Our three files are starting to develop like this:

square
public class Square{
   private double length;

   public double calcArea(){
      return length * length;
   }
right triangle
public class RightTriangle{
   private double base;
   private double height;

   public double calcArea(){
      return 0.5 * base
             * height;
   }
circle
public class Circle{
   private double radius;

   public double calcArea(){
      return Math.PI * 
             radius * radius;
   }

When we make these separate files, we no longer use the static access modifier on the class because we will be making objects to invoke their methods with dot notation. We use the private access modifier on the attributes (AKA data fields or instance variables) of the object so that we don’t give the programmer direct access to them from other files (we would use public if we did want to give direct access from other files).

These classes that combine attributes and methods that manipulate the attributes are called data types – a way of packaging together values and ways of manipulating those values. When objects (set to variables) are made out of these data types, their constructor is called. A constructor is simply a special public method that takes potential parameters and makes an object, i.e. an instance or an occurrence of, that item in the computer’s memory.

Add Constructors to Square, Right Triangle, Circle#

Constructors should be defined in each data type, and have the same name as the data type with no return type (not even void). Their parameters consist of data necessary for the initialization of the object. The constructor is called by using Java’s new reserved word. Our code now looks like this, with constructors added:

square
public class Square{
   private double length;

   public Square(double len){
      length = len;
   }

   public double calcArea(){
      return length * length;
   }
right triangle
public class RightTriangle{
   private double base;
   private double height;

   public RightTriangle (double 
          base, double height){
      this.base = base;
      this.height = height;
   }

   public double calcArea(){
      return 0.5 * base
             * height;
   }
circle
public class Circle{
   private double radius;

   public Circle(double radius){
      this.radius = radius;
   }

   public double calcArea(){
      return Math.PI * 
             radius * radius;
   }

Can you identify the constructors? Notice how in the constructor for Square, the parameter (len) has a different name from the instance variable (length). In this case, the assignment is straightforward, placing the value of the parameter into the instance variable. In the constructors for RightTriangle and Circle, the parameters have the same name as instance variables. Thus, the reserved word this is used to distinguish the instance variable from the parameter. Again the values of the parameters are copied into the instance variables.

Use the New Classes, AKA User-Defined Data Types#

It is beautiful when we see how we can use these new data types. In a fourth file, the file with your main program, we can now create objects of each of these types and then print out their areas. Here is an example:

public static void main(String[] args) {
   Square mirror = new Square(5);
   RightTriangle cornerMold = new RightTriangle(3, 8);
   Circle plate = new Circle(4);
        
   System.out.println("mirror area: " + mirror.calcArea());
   System.out.println("cornerMold area: " + cornerMold.calcArea());
   System.out.println("plate area: " + plate.calcArea());
}

Notice the simplicity of this program. We don’t have to write any if statements to determine what the data type of an item is. Nor do we really have to think about it much ourselves, aside from our initial declaration. The objects calculate their areas properly. We send the same dot message to each (because the programmer of those data types used the same name, thankfully), but each performs a different calculation.

In this example of the shapes, I showed you three different data types. You can use the same ideas with even just one data type when there happens to be one noun that is critical to the creation of your project.

Practice Questions#

  1. Write a method called calcPerimeter for each of a Square, a RightTriangle, and a Circle.

  2. Write the code to print the perimeter of each of mirror, cornerMold, and plate, as defined in main above.

  3. What are the instance variables of mirror? The methods/operations of mirror?

  4. What are the instance variables of cornerMold? The methods/operations of cornerMold?

  5. What are the instance variables of plate? The methods/operations of plate?

To Solutions