Karan Khanna
Karan Khanna

Reputation: 2157

Understanding Encapsulation in OOP with code

Trying to understand the concept of encapsulation, I came across this definition "Combining the attributes and methods in the same entity in such a way as to hide what should be hidden and make visible what is intended to be visible".

But practicing the same, I am not sure which of the following code is more apt for OOP:

public class Square {

    //private attribute
    private int square;

    //public interface
    public int getSquare(int value) {
        this.square = value * value;
        return this.square;
    }
}

or

public class Square {

    //private attribute
    private int square;

    //public interface
    public int getSquare(int value) {
        this.square = calculateSquare(value);
        return this.square;
    }

    //private implementation
    private int calculateSquare(int value) {
        return value * value;
    }
}

Upvotes: 1

Views: 164

Answers (3)

inquisitive
inquisitive

Reputation: 3649

Combining the attributes and methods in the same entity in such a way as to hide what should be hidden and make visible what is intended to be visible

This is a potentially misleading statement. You are NOT hiding anything from anyone. It is also not about methods or fields. Unfortunately this is the way things are worded in almost every place.

How

When writing any piece of program, (be it a function, class, module, or library) we think of the piece we are working on as my code, every other code as my client code. Now assume that all the client code is written by someone else, NOT you. You write just this code. Just assume this, even if you are the only one person working on the entire project.

Now the client code needs to interact with my code. So my code should be nice and decent to talk to. The concept of encapsulation says, that I partition my code in two parts, (1) that the client code should be bothered with, (2) that the client code should NOT be bothered with. The OO way of achieving encapsulation is by using keywords like public and private. The non OO way of achieving this is naming convention like leading underscores. Remember, you are not hiding, you are just marking it as none-of-your-business.

Why

So why should we encapsulate things? What should be organize my code into public and private regions? When someone uses my code, they are of-course using the whole thing, not just public thing, so how come private is something that is none-of-their-business? Note here words like someone and their could refer to yourself - but only while working on the other piece of code.

The answer is easy testability and maintainability. A complete project if tested exhaustively, can be quite a task. So at minimum, when you are done coding, you just test the public aspects of my code. You do not test any of the client code, you do not test any of the private aspects of my code. This reduces test effort while preserving sufficient coverage.

Another aspect is maintainability. My code will NEVER be perfect, it WILL need revisions. Either because of bugfix or enhancement, my code will need tinkering. So when a new version of my code is available, how much is client code impacted? None, if changes are in private regions. Also, while planning a change, we try to confine it as much as possible in private regions. So the change, from client's perspective becomes a no-impact. A change in public aspects of my code, will almost always require changes in client code, now that will need testing. While planning the big picture of my code, we try to maximize the area under private regions and minimize the area under public regions.

And more

The idea of encapsulating links with the idea of abstracting which in turn links with idea of polymorphism. None of these are strictly about OO. Even in non OO world like C or even Assembly, these apply. The way to achieve these differ. Even this applies to things beyond computers.

The process of sewage management, for example, is

encapsulated within the public interface of drains. The general public bothers only with the drains. The treatment, the disposal, the recycling are none of general public's business. Thus, the sewage management could be treated as an -

abstract entity - an interface with just the drains. Different government and companies implement this in their own way. Now an city may have a permanent system of sewage management, or it can periodically -

switch providers. In fifty years of government operation, the situation was bad, but once they contracted that BigCorp Inc, now people can breathe free. We just did polymorphism. We switched implementations, keeping the public interface same. Both government and the BigCorp Inc use the same drains, but their own processing facilities, which are encapsulated away and polymorphically switchable.

In your code

In both your codes you chose to encapsulate the storage, the field is made private. This is a nice approach and certainly OO way. In both of your codes, the algorithm is also encapsulated - i.e not visible to the client. Nice. In your second code, you went ahead and extracted the algorithm in a separate non-public method. This is commendable approach, although obviously an overkill for doing something trivial. Better OO none the less.

What you did in second code even has a name: the strategy pattern. Even though here it is useless (and overkill), it could be useful in a scenario when let say you are dealing with extremely large numbers, such that calculating their squares take very long time. In such a scenario, you could make your calculateSquare method protected, have a class FastButApproxSquare extends Square, and override the calculateSquare method with a different algo which calculates an approx value much faster. This way you could do Polymorphism. Whoever needs exact value will use the Square class. Whoever needs approx value will use FastButApproxSquare class.

Upvotes: 2

Harmlezz
Harmlezz

Reputation: 8078

Encapsulation is about hiding implementation and structure details from client code. In addition it is about coherence: keep things close together which are highly related to each other.

For example consider a class which manages players of a football team:

public class FootballTeam {
    public final List<Player> players = new ArrayList<>();

}

Client code would have access to the list of players, to look them up, to add players and so on:

public class FootballManager {

    private final FootballTeam team = new FootballTeam();

    public void hirePlayer(Player player) {
        team.players.add(player);
    }

    public void firePlayer(int jerseyNo) {
        Optional<Player> player = team.players.stream()
                .filter(p -> p.getJerseyNo() == jerseyNo)
                .findFirst();
        player.ifPresent(p -> team.players.remove(p));
    }
}

Now, if someone decides to change the field FootballTeam.players into a Map<Integer, Player>, mapping the players jersey number to the player, the client code would break.

In addition the client code deals with aspects / features closely related to a player. To protect the client code and to ensure changeability of the FootballTeam implementation hide all implementation details, keep player related functionality close to the structure, representing the team and reduce the public interface surface:

public class FootballTeam {

    private final Map<Integer, Player> players = new HashMap<>();

    public void addPlayer(Player player) {
        players.put(player.getJerseyNo(), player);
    }

    public Optional<Player> lookupPlayer(int jerseyNo) {
        return Optional.ofNullable(players.get(jerseyNo));
    }

    public void remove(Player player) {
        players.remove(player.getJerseyNo());
    }
}

public class FootballManager {

    private final FootballTeam team = new FootballTeam();

    public void hirePlayer(Player player) {
        team.addPlayer(player);
    }

    public void firePlayer(int jerseyNo) {
        team.lookupPlayer(jerseyNo)
                .ifPresent(player -> team.remove(player));
    }
}

Upvotes: 1

Obayed Bin Mahfuz
Obayed Bin Mahfuz

Reputation: 1

If any code serves the purpose of encapsulation then that code is correct. The purpose of encapsulation is to provide a process of hiding the variables from other classes (i.e. by making the variable as private) and also to provide a way for other classes to access and modify the variables. Both of your code serves this purpose correctly.

If you would have used "calculateSquare(int value)" method as "public" then there would have been a problem. Other class could call this method directly without using set/get method. So as far as your this method is "private" I think both the codes are all right.

Upvotes: 0

Related Questions