Creating Objects in Java (part 1)

In this post, we discuss about creating objects in Java. Wait a minute. Why I want to talk about this? Well, creating objects in Java is “easy”. Java is an Object-oriented programming language, creating objects is the simplest thing of it.

When the thing looks easy, sometimes, it might drive you lost.

Contents
1. Introduce
2. JavaBeans Pattern
3. Builder Pattern

Introduce

When you start learning Java, you will quickly get to know how to create an object. That is:

MyClass myObject = new MyClass();

For example:

Cat myCat = new Cat(3, 25);

Everything looks simple. Right?

The method we are using to create object “myCat” is called “public constructor”. And we can create “multiple” constructors for a class. That means, we can have “many ways” to create a class’s instances.

public class Cat {
  public enum Color { WHITE, BLACK, RED, BLUE, CHOCOLATE }

  private int age;
  private int weight;
  private int length;
  private Color color; 

  public Cat() {
  }

  public Cat(int age) {
    this.age = age;
  }  

  public Cat(Color color) {
    this.color = color;
  }
  
  public Cat(int weight; int length) {
    this.weight = weight;
    this.length = length;
  } 
 
  public Cat(int age, int weight; int length) {
    this.age = age;
    this.weight = weight;
    this.length = length;
  }
 
  public Cat(int age, int weight; int length, Color color) {
    this.age = age;
    this.weight = weight;
    this.length = length;
  }

  // Getters & Setters
  // ...

}

Looking at the class above, what you can see? We have a lot of fields, and a lot of “constructors” also. And this is call “telescoping constructor pattern“.

Now the thing is more complicated. Look cat this:

Cat myCat = new Cat(2, 3, 25, Cat.Color.BLUE);

We can only easy to learn that the fourth parameter mention about the “cat’s color”. However, the first 3 parameters, how to know which is the age, which is the weight, and which is the length? The order of “2, 3, 25” has no meaning to understand.

Some people will say: “OK. I will add Java Doc to each public constructors. So the IDE will show it when I need.”.

Well. Documentation is very great. However, it makes you take more time to understand the codes. To be honest, the code above is hard to read.

Why we do not make the code clear, short, and easy to understand (before reading the documents)?

JavaBeans Pattern

We should avoid creating a lot of public constructors like the example above. It is not good.

The telescoping constructor pattern is not good to scale your codes. Especially in large projects / programs.

We should always know the meaning of the input parameters to create objects in the right ways. We can pass parameter in the right type, but wrong meaning. The compiler will not complain you. However, we might get runtime bugs / errors.

One of the way to avoid many parameters in a constructor is Java Bean Pattern. Well, in simplest explanation, the main point of this pattern is: setter (and getter).

public class Cat {
  public enum Color { WHITE, BLACK, RED, BLUE, CHOCOLATE }

  private int age;
  private int weight;
  private int length;
  private Color color; 

  public Cat() {
  }
  
  // Setters
  public void setAge(int age) { this.age = age; }
  public void setWeight(int weight) { this.weight = weight; }
  public void setLength(int length) { this.length = length; }
  public void setColor(Color color) { this.color = color; }

  // Getters
  // ...
}

We deleted almost constructors, but keep the default constructor. Now, to create the cat & set it’s values, we doing as following:

Cat myCat = new Cat();
myCat.setAge(2);
myCat.setWeight(3);
myCat.setLength(25);
myCat.setColor(Cat.Color.BLUE);

In this example, we can easy to know which value we are setting. It is very clear to know which value is age, which value is length, etc.

Unfortunately, there are some disadvantages of this pattern.

To make the “construction” completed, we must to do multiple calling. At the time object creating, its data is not FULLY set. And if you “forgot” to set the data, the data might be lost. And again, the compiler will not complain you, but the runtime bugs might come.

Moreover, because, we can modify the data at many places in the program, it will make the data might be “inconsistent”. To avoid this, we should use “immutable objects”. I will write another post to introduce about this topic.

Builder Pattern

Actually, JavaBeans benefit is encapsulating (multi) data into a single object that make they are serializable. That mean you can transfer (complex) data between components of a systems or multiple systems. This is very important in “reusable software components” or Java Web Development. However, we should be very careful while using this pattern to make sure the data is not inconsistent or no losing data.

To avoid of “losing” or “inconsistent” data before the object is used. We, should avoid using the object before all of its data are initialized.

Which JavaBeans pattern, we CANNOT promise that we will not use the object before all its data are initialized.

The Builder Pattern & “immutable objects” will help us a lot on this.

With this pattern, we can combine the benefits of telescoping constructor pattern and JavaBean pattern:

– We can have the safety of telescoping constructor pattern: NOT use the objects before all of their data are initialized.

– We can make the code will be clear & easy to read like JavaBean pattern.

To implement this pattern, we following these instruction:

– No public constructors: every instance of your class should be created by the Builder. This we help us has a way to “validate” our data before using them.

– Make all properties to be “final” to ensure not allow to used object before all data are initialized.

– Write the Builder class as your class public static nested class.

But why we should write the Builder as an public static nested class?

This will make the Builder more clear what it is used for. For example: CatBuilder is not clear which class to create instance. The package1.Cat or package2.Cat?

With Cat.Builder, it will be clear the Cat.Builder class for sure to create instances for its outer class. Moreover, it will help the outer class can access directly to the builder properties. We will not want write very long class with unnecessary getters & setters, right?

But why it is “public static”? First, if it is not “public”, we cannot use it out side of the class. And if we do not make the class is “nested” (static class inside another class), we cannot create a Builder instance without creating the outer class.

public class OuterClass {
  public class InnerClass {
  }
}

OuterClass outerClassInstance = new OuterClass();
OuterClass.InnerClass innerClassInstnace = new outerClassInstance.InnerClass();

So, the instance of InnerClass above can only exists within the instance of OuterClass.

Now, we can write a Builder for our Cat class.

public class Cat {
  public enum Color { WHITE, BLACK, RED, BLUE, CHOCOLATE }

  private final int age;
  private final int weight;
  private final int length;
  private final Color color; 

  public static class Builder {
    private int age;
    private int weight;
    private int length;
    private Color color;  
    
    public Builder() {}

    public Builder age(int value) { this.age = value;  return this; }
    public Builder weight(int value) { this.weight = value;  return this; }
    public Builder length(int value) { this.length = value;  return this; }
    public Builder color(Color value) { this.color = value;  return this; }

    public Cat build() {
      return new Cat(this);
    }
  }

  private Cat(Builder builder) {
    this.age = builder.age;
    this.weight = builder.weight;
    this.length = builder.length;
    this.color = builder.color;
  }

  
  // Getters 
   ...
}

To create the Cat instance by the Builder:

Cat myCat = new Cat.Builder()
                   .age(2)
                   .weight(3)
                   .length(25)
                   .color(Cat.Color.BLUE)
                   .build(); 

So, the builder setter methods to set its data has no “set” prefix for their name. And these method is return the builder itself. As you can se, in the statement of creating the “myCat” object, it looks like a “chain”. This is called fluent API concept.

I hope this post will help you to get more information about creating object in Java with common patterns.

In the next post, I will introduce more about the Builder Pattern.

Saigon, Nov 22, 2020
Hau Nguyen / Jason.

Credits:
Cover Photo by Michiel Leunens on Unsplash

Gửi bình luận