Search code examples
javaoopinheritanceencapsulationcomposition

Encapsulation in the Java Model Class


Let assume that we develop a simple blog website backend and the app have three or more POJO classes like Post, User, Category.

All class have the same fields such as id, createdDate, updateDate.

As java-programmers, we apply Encapsulation to all the fields in a class using private access modifier. My question is very simple: Can we perform encapsulation using default access modifier with Inheritance?

The code:

public abstract class BaseModel {
    String id;
    LocalDateTime createdDate;
    LocalDateTime updatedDate;
    // getters and setters
}

public class Post extends BaseModel{
    private String slug;
    private String name;
    private String title;
    // other fields, getters and setters
}

public class Category extends BaseModel{
    private String name;
    private String slug;
    // other fields, getters and setters
}

Solution

  • Protected modifier

    The common practice it to use protected access modifier to encapsulate class members within the Parent class.

    Package private fields and methods will not be visible to subclasses located outside the package of the Parent class. Conversely, protected variables and behavior will be accessible to any subclass regardless of its location.

    Composition vs Inheritance

    Inheritance is not always beneficial, in-fact there are many cases where it isn't. You need to consider all pros and cons before making class-design decisions like whether a particular class will derive from another class.

    What are the benefits of extending the BaseModel?

    It doesn't feel like you can take advantage from the polymorphism here. Because the only behavior you can use with the parent type BaseModel are getters and setters for dates of creation and update. And at the same time you'll not be able to access the specific behavior of subclasses.

    It looks rather as a drawback because BaseModel isn't designed for extension. I.e. it neither contains any useful implementations (I'm not taking getters/setters into account), no abstract methods are meant to be implemented by its subclasses (that would be a scenario of advantageous polymorphism).

    In fact, you are extending BaseModel just in order to reuse a couple of variables. That not a compelling reason to utilize inheritance.

    Your example is a perfect case to substitute an IS A relationship (Post is a BaseModel) with HAS A relationship (Post includes BaseModel).

    The design technic, when a class contains its instance field an instance of another class instead of extending this class, is called Composition.

    As a general rule, composition is a more preferable approach than inheritance. As well as inheritance, it allows to reuse the behavior and at the same time it classes closely coupled.

    If you make the BaseModel a concrete class and apply composition to other classes, your code will look like that.

    public class BaseModel {
        private String id;
        private LocalDateTime createdDate;
        private LocalDateTime updatedDate;
        // getters and setters
    }
    
    public class Post {
        private BaseModel base;
        private String slug;
        private String name;
        private String title;
        // other fields, getters and setters
    }
    
    public class Category {
        private BaseModel base;
        private String name;
        private String slug;
        // other fields, getters and setters
    }