How does encapsulation prevent unwanted access by bundling functions and variables?

Viewed 29

I came across two characteristics of encapsulation

  1. Bundles functions and variables into a single entity.
  2. Prevents unwanted access to functions/variables by guiding implementation.

I understand that both these characteristics are individually important but I can't figure out if they're related.

Does bundling somehow prevent unwanted access or does preventing unwanted access require bundling?

1 Answers

Yes, of course. Let's say I have 2 aspects (a functionality, and a variable):

The variable represents the birth year of the user.

The functionality is twofold:

  • Check and refuse any attempt to set birth year into the future, or more than 200 years in the past.
  • If the birth year indicates the user is less than 18 years of age, remove the alcohol products from the UI. Otherwise, show them.

With encapsulation, you'd have a single method that 'sets the birth year' that does all 3 at once (it changes the birth year variable, but only after the checks, and it notifies the UI layer about minority status).

In a non-bundled/non-OO approach, you'd presumably have:

  • A separate (in java terms static) method that simply checks if a given birth year would be valid, and if not, what error one should provide. Call it checkYear.
  • A separate (in java terms static) method that will check a provided birth year (not the actual property, just any parameter) for minority status or not and convey this to an also provided UI layer.
  • A publicly editable property.

So, the 'birth year widget' would presumably:

  • First take the new value and toss it through checkYear. If it reports an error, snap the year widget back to the old value, and convey this error via the UI.
  • Otherwise, update the property.
  • Also, fetch the 'UI layer' property, then, call the static function that takes in a birthyear and a UI layer and will convey 'show alcohol or not' to it.

By not being encapsulated, you:

  • Need to leak implementation manuals to users of your code (you now need to explain that changing the birthyear is a complex song-and-dance routine with many steps).
  • Severely limit your ability to change and expand features later on. If the 'show alcohol or not' thing is a later idea, with encapsulation you just change the setBirthYear method. Without it, you need to find all code that changes birth year and retroactively modify them all to call the updateShopSelection method. This is much more work and could be impossible, if the callers are out of your control (example, you're a library author, you do not control the code that uses your library).
  • Avoid invalid state. It is now simply impossible for any code that isn't in the User.java file (or whatever has the birthyear property) to create a scenario whereby birthyear is set to an invalid value, or set to sub 18 but the UI hasn't been informed to remove alcohol products. That's nice; you now no longer need to consider it when figuring out how things work, why a bug occurred, or how code should act in the face of inconsistent state (because there cannot be inconsistent state). Without encapulation you're relying on all users of your code to never be inconsistent, and, in multithreaded environments, to lock appropriately. Good luck with that.

Of course, on the down side, encapsulation:

  • Tends to be a black box every time; most methods have 'side effects' and the whole point is that these aren't really known in advance. Makes it hard to reason about what a method call will actually do.
  • As a consequence convoluted purely functional approaches which don't work nearly as well if side-effects are a thing. For example, memoizing (remembering what the return value was for a given method call for a specific set of parameters, then the next time some other code calls the same method with the same values, just return the remembered result. This doesn't work if the method does more than simply calculate things in stable ways with no further effects).
Related