Monday, 11 July 2022

Why should we restrict direct access to instance properties?

In this post, I am going to explain what are instance properties and what will go wrong, if we make the instance properties public etc.,

 

Instance properties or instance variables

Instance variables are those which are associated with an object.

 

For example, employee object has below instance properties.

a.   id

b.   firstName and lastName

c.    emailId

d.   address etc.,

 

It is not necessary to make all the instance properties private, some might be protected, default and public also. But we can get encapsulation (Encapsulation is the technique of restricting the direct access to the data, data can accessed via methods)  benefits, if we restrict the access to instance properties via methods.

 


Let’s us discuss with an example on what will go wrong, if we directly access the instance properties.

 

Employee.java

package com.sample.app.dto;

public class Employee {
	public int id;
	public String firstName;
	public String lastName;
	public String email;
}

 

Since I made the instance properties public, I can directly access them outside of the class.

 

a. Assume employee name must not be null, Since I can access the name property outside of the class, I can still set employee name to null value.

Ex:

emp1.firstName = null;

emp1.lastName = null

 

b. Employee id must be > 1. But I can violate this constraint, by directly setting employee id to some negative value.

 

Ex:

emp1.id = -123;

 

c. I can set email with some random data.

 

 

Ex

emp1.email = "123456";

 

c. You will lose control on the data like how the data is used, how to update in multi-threaded environment etc.,

 

d. By exposing the properties directly, you are exposing the objects internal state, which is a bad design.

 

Benefits that we are getting by exposing the instance properties via setter and getter methods

 

a. We can apply data validation constraints.

 

‘id’ must be > 0. 

public void setId(int id) {
	if (id < 0) {
		throw new IllegalArgumentException("id must be >= 1");
	}

	this.id = id;
}

 

‘firstName’ and ‘lastName’ must not be null and empty

public void setFirstName(String firstName) {
	if (firstName == null || firstName.isEmpty()) {
		throw new IllegalArgumentException("firstName must not be null and empty");
	}

	this.firstName = firstName;
}

public void setLastName(String lastName) {
	if (lastName == null || lastName.isEmpty()) {
		throw new IllegalArgumentException("lastName must not be null and empty");
	}

	this.lastName = lastName;
}

‘email’ validation check

public void setEmail(String email) {

	if (email == null || email.isEmpty()) {
		throw new IllegalArgumentException("email must not be null and empty");
	}

	if (!EmailUtil.validate(email)) {
		throw new IllegalArgumentException("email is not valid");
	}

	this.email = email;
}

b. We can design read-only fields, on demand read only information.

 

For example, we can form employee full name by concatenating employee first and last names.

public String getFullName() {
	return this.firstName + "," + this.lastName;
}

c. We can apply some conversions, while sending the data.

 

For example, as per the use case, I need to send employee first and last names in upper case.

public String getFirstName() {
	return firstName.toUpperCase();
}

public String getLastName() {
	return lastName.toLowerCase();
}

Find the below working application.

 

EmailUtil.java

package com.sample.app.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EmailUtil {

	public static final Pattern EMAIL_REGEX = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$",
			Pattern.CASE_INSENSITIVE);

	public static boolean validate(final String emailStr) {
		final Matcher matcher = EMAIL_REGEX.matcher(emailStr);
		return matcher.find();
	}

}

Employee.java

package com.sample.app.dto;

import com.sample.app.util.EmailUtil;

public class Employee {
	private int id;
	private String firstName;
	private String lastName;
	private String email;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		if (id < 0) {
			throw new IllegalArgumentException("id must be >= 1");
		}

		this.id = id;
	}

	public String getFirstName() {
		return firstName.toUpperCase();
	}

	public void setFirstName(String firstName) {
		if (firstName == null || firstName.isEmpty()) {
			throw new IllegalArgumentException("firstName must not be null and empty");
		}

		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName.toUpperCase();
	}

	public void setLastName(String lastName) {
		if (lastName == null || lastName.isEmpty()) {
			throw new IllegalArgumentException("lastName must not be null and empty");
		}

		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {

		if (email == null || email.isEmpty()) {
			throw new IllegalArgumentException("email must not be null and empty");
		}

		if (!EmailUtil.validate(email)) {
			throw new IllegalArgumentException("email is not valid");
		}

		this.email = email;
	}

	public String getFullName() {
		return this.getFirstName() + "," + this.getLastName();
	}

}

App.java

package com.sample.app;

import com.sample.app.dto.Employee;

public class App {
	public static void main(String[] args) {
		Employee emp1 = new Employee();

		emp1.setId(123);
		emp1.setFirstName("Lahari");
		emp1.setLastName("Gurram");
		emp1.setEmail("test@abc.com");

		System.out.println("id : " + emp1.getId());
		System.out.println("firstName : " + emp1.getFirstName());
		System.out.println("lastName : " + emp1.getLastName());
		System.out.println("fullName : " + emp1.getFullName());
		System.out.println("email : " + emp1.getEmail());

	}
}

Output

id : 123
firstName : LAHARI
lastName : GURRAM
fullName : LAHARI,GURRAM
email : test@abc.com



 

You may like

Interview Questions

What are the different cache eviction strategies?

How to call super class method from sub class overriding method?

Can an enum has abstract methods in Java?

Can enum implement an interface in Java?

What happen to the threads when main method complete execution

Why System.out.println() is not throwing NullPointerException on null references?

No comments:

Post a Comment