Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Object Modeling Best Practices

DZone 's Guide to

Object Modeling Best Practices

OOP is all about encapsulation.

· Java Zone ·
Free Resource

OOP Is All About Encapsulation

Yes, that’s right. Object-oriented programming aims to encapsulate properties and methods into a consolidated object so that operations can be carried out on the object. The whole aim is to move away from procedural functions, which are not easy to reason with or prove correctness. But this principle often gets violated and people write procedural code using objects. Here is a classic example:

class Rectangle {
    private Long length;
    private Long breadth;

    //gettters
    //setters
    //constructors
}


And caller calculates area by:

Rectangle r = new Rectangle (3,4);
System.out.print("Area is: "+(r.getLength()*r.getBreadth());


This is a very bad example of misusing objects. This is, in fact, procedural, non-encapsulated code, which just happens to use the object. This example could be worse if we had an empty constructor for Rectangle.

Rectangle r = new Rectangle();
r.setLength();
r.setBreadth();


Again, this is a terrible misuse of objects. We have created an object that is impossible to reason with regarding its correctness/completeness. I think such behavior is encouraged because we start off writing an empty constructor and public getters/setters as soon as we declare a class. I have realized that this is, indeed,  very bad practice. More so, this is something that encourages programmers to violate the basic foundations upon which OOP was built.

1. Don’t Write Empty Constructors

Don’t let your objects be created statelesss. Having empty objects makes the code very hard to reason with. You can never rely on what the state of the object is. Imagine sending your friend to do something for you (make coffee, for example) and your friend goes. But wait, he can’t walk because he doesn’t have legs, or maybe can’t prepare it because he doesn’t have hands. See, you can’t reason with the state of your object (friend) — unless there is a valid, reasonable scenario (Jackson object mapper comes to mind) to avoid the use of empty constructors.

By avoiding empty constructors, we avoid the scenario where the object can be in an inconsistent state. This also avoids the cases for programmers to have public setters.

2. Don’t Start Off With Exposing All the Getters

It’s very convenient and tempting to start off by exposing all the public getters. But this is a serious violation of the encapsulation principle. We might genuinely need some public getters (toStringcomes to mind) but add those only when required strictly.

  • Before you get from an object, think about why. What are you going to do with that value? Are you going to calculate something? Then, is it not better to have it modeled as a method within the object. This would largely improve the consistency wherever the object is used within the code.

In our above example, we realized we needed to calculate the area of Rectangle much longer after the object was created (a valid scenario, we can’t always have a clear insight). Instead of getting length and breadth and multiplying, them we should think about whether we can obtain by still maintaining the encapsulation.

Example of Good Encapsulation

class Rectangle{
    private Long length;
    private Long breadth;

    public Rectangle(Long length, Long breadth){
        this.length=length;
        this.breadth=breadth;
    }

    public Long getArea(){
        return this.length*this.breadth;
    }
}


Now, this is fairly better encapsulation. We don’t have empty constructor and setters either. We can fairly reason that if there is a rectangle object, it’s a consistent and valid one. If someone wants to compute the area of that object, there is a consistent method that serves the purpose eradicating the need of public getters.

Topics:
java ,oop ,object ,object abstraction ,encapsulation ,best practices

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}