More about Setter and Getter and OOP

Jorge Castro
Cook php
Published in
8 min readJun 3, 2019

It is for business projects.

Architecture

Business Object

In the past, our architecture was composed of classes called “Business Object” (it also has some other names but the idea is the same), it was a type of class that contains logic (functions) and store values (aka fields).

For example, let’s say we have a system that manages Customers.

It works fine for small projects. It’s not rare to find books and manuals talking about this kind of classes. But they are not scalable and it presents some troubles. So, we split this class in two:

Anemic Object aka Model

It’s a class that stores values it should lack logic.

public class Customer {
private String age;
private String name;
private String prefix;
// setter and getters goes here...
}

It is our class in the database

And it is our class via rest service

{"age":10,"name":"John","prefix":"Phd"}

It could have logic but it is not recommended.

Service Class

Contrary to the Model class, the service class lacks fields while it contains the logic (method/functions).

public class CustomerService {    
public void showMe() {
System.out.println("My name is "+name);
}
}

Why we split the class?.

It is because is easy to debug and to maintain the code. It also helps to escalate the project and to add new functionalities without breaking other code.

For example, let’s say we want to add methods that connect to the database

public class CustomerMySql {   // usually it is called CustomerRepo etc.
public List<Customer> listAll() {
// our code
}
}

What is it?. A service class. In fact, we could have as many service class as we want to.

So, we also separate the service classes in categories, commonly:

  • Repository, DAO, DAL classes (that connects to the database)
  • Web Service classes.
  • Logic Classes (such as validations, factory, and such)
  • Others.

And again, why? Because it’s easy to debug and to maintain the code. Let’s say we have a problem, our system is unable to insert a customer into the database. So, we find the namespace (MySql), then we find the class that starts with Customer and we found the method.

Question: But what about setter and getter?.

Well, in our Model class, we are adding logic, logic that most of the time is useless!.

It is logic:

public class Customer {
// ....
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}

We could use Lombok (it is highly recommended) to HIDE it but it is still logic.

@Getter @Setter // lombok
public class Customer {
private String age;
private String name;
private String prefix;
// we don't need setter and getter.
}

Lombok works at compile time, so it is the same to add code before it is compiled (but the code is added anyways).

Question: But OOP

But OOP requires encapsulation.

OOP is not a law, its a guideline.

Question: What is the problem with setter and getter?

Code clarity.

It is how we use the model with setter and getter.

Customer cus=new Customer();
cus.setName("John");
System.out.println("The age is "+cus.getAge());

And it is the version with public fields.

Customer cus=new Customer();
cus.name="John";
System.out.println("The age is "+cus.age);

Question: We couldn’t add logic with public fields, are we?

Let’s say the next code

public void setName(String name) {
this.name = name;
this.prefix="Junior";
}

So if we modify the name then we also modify the prefix. The problem to add logic in the setter and getter it is not obvious.

For example:

Customer cus=new Customer();
cus.setPrefix("Dr.");
cus.setName("John");
// it will return Junior John instead of Dr. John.

Adding logic to the setter and getter is usually evil.

Also, we could write the logic in the service class, where it is easy to debug and test.

Question: We should encapsulate the values.

Yes, but it is not solved by setter and getter!.

For example, let’s say our model contains a new field (it’s an object)

public class Customer {
private String age;
private String name;
private String prefix;
private Category category;
// setter and getters
}
public class Category {
private String nameCategory;
// setter and getters
}

So we use as

Customer cus=new Customer();
cus.setName("John");
cus.getCategory().setNameCategory(""); // Using get to set a value @_@.

So our getter not only lacks encapsulation but it is also not clean.

Question: Then, how we could encapsulate values?.

First, every (JAVA but it also applies for other languages) developer must understand the difference between primitive versus object and the difference between by value and by reference.

We could also encapsulate the value by creating a clone but we don’t do for obvious reasons.

Also, if we read a value that it must be immutable then why we are modifying it?. And it is here where we apply SRP (Simple Responsibility Principle), we do one task at the same time: or we modify the value or we read the value, not both.

We couldn’t do Unit test without setter and getter.

I hear it often

We must not do Unit test of code generated (because it’s cheating!). Also, we mustn’t do unit test of trivial code. It affects the code coverage however, the code coverage is just a number, not a measure of something worth (really). Many developers play the system by increasing the code coverage artificially.

We couldn’t use Interface without setter and getter.

Interface is useful because we could reuse code.

Some java coders create one Interface = One class and it is SO WRONG but I’m not talking about it.

And about SOLID (I = Interface)

SOLID is a guideline, not a rule.

But about Interface, let’s say we have the next models:

  • Customer (age, name, prefix)
  • Employee (age, name, company)

So it could make sense to create an interface if not an inheritance. (tips: not really).

  • Person (age, name)

So our classes are implemented as

public class Customer implements Person {
// implementation
}
public class Employee implements Person {
// implementation
}
public interface Person {
String getName();
void setName(String name);
String getAge();
void setAge(String age);
}

However, the use of Interface adds DEPENDENCY.

Now, let’s say we don’t want to hold the age of the Customers. If we modify the interface, then we also modify the class Employee, ergo we found a problem because we added a dependency.

Interfaces are right if they are used with a clear purpose but it is also a double edge sword.

Also, it’s hard to debug code with Interface.

Let’s say this code fails:

SomeInterface object;
// it fails somewhere here.

Question: what is the class of the object?

However

Not every object is similar. For example, a visual object, a button:

In the case of a visual object, we don’t use a Model+Service classes pair but a Bussiness Object class (a class with fields and functions). Why?. Because they fit better than an anemic model + service class.

public class MyButton {
private String Title;
private int width;
private int height;
private int top;
private int left;
// setter and getter also functions
}

We could also add logic to the setter and getter.

public class MyButton {
//....
public int getXRight() {
return left+width; // we can use a getter with logic without a field.
}
public void setWidth(int width) {
if(width<100) {
width=100;
}
this.width = width;
}
}

Also

Sometimes we want to standardize the code, i.e. we don’t want to see one style for one class and another style for another class.

Also (more)

Some libraries require the use of setter and getter. JSF used to rely on setter and getter (but not anymore, we could use public fields).

So, there is not a one-solution-fits-all.

More about Java.

The Java Runtime Engine is sneaky and it understands the setter and getter. It optimizes the result code, so if we add a regular setter and getter (without extra logic), then the JRE acts the same than a public field.

Final world.

but, can we use a model class with public fields?. Yes. C works in this fashion (C is not OOP) and some other languages.

struct account {
int age;
char *name;
char *prefix;
};

We usually use setter and getter because they are generated automatically (via refactorization or Lombok) but we use it automatically then, the JIT compiler ends removing it anyways.

JIT removes automatically most setter and getter that were generated, ahem automatically, so why are we adding?

People forget that (we) developers are (still) humans.

For example and I will repeat myself

object.getField().getOtherField().getOhNoesAnotherField().setFinalField("Some Name");

It is not clear, while (using public fields)

object.field.otherField.ohNoesAnotherfield.finalField="Some Name";

It’s not only short to write but also to understand.

As a note code like this one:

object.getField().getOtherField().someMethod<Class,OtherClass>(arg,moreargs); // is cringe

C# solved it by pleasing every pro encapsulation versus against encapsulation by creating properties. So in C# we used:

object.Field.OtherField.OhNoesAnotherField.FinalField="Some Name";

Java doesn’t have it and it is a shame.

Example

Let’s say we want to show the customer but we need a new column (id), it must be generated automatically and we couldn’t generate on the view/template layer.

We don’t need to poison our model class with a new setter and getter.

public class CustomerUI extends Customer {
private int id;
public int getId() {
id=id+1;
return id;
}
}

So this class works specifically to solve a visual problem. We could remove the setter and getter of the Customer class while we retain some logic.

Note: Also published on

--

--