7

This site and SO contain many pages about getters/setters and if they break encapsulation or enforce it. My question is for those developers that agree that getters/setters break encapsulation and should be avoided.

Questions:

  1. How do you display your data in a GUI if necessary without getters? I found this link, but to me it seems kind of strange for your class to be aware of components to display.
  2. To quote from this link:

It is certainly true that having getters and setters for every field provides little more encapsulation than having those fields be public, and it's unfortunate that this kind of design is very widespread.

What if you designed a class where all the properties have getters for displaying, now I understand someone could call the getters and use them for calculations and behaviors other than displaying, but my point is, if you find it nessesary to provide getters for all your private variables to display, should you be rethinking your design? if so, how?

I'm not talking about if when getters/setters are justified, but rather when display properties of an object, if you're providing getters/setters for all your properties, should you be rethinking your design?

  • Possible duplicate of When are Getters and Setters Justified – gnat Jun 28 '17 at 14:21
  • @gnat - I'm aware of those pages, but my question concerns two things that aren't addressed in those pages. – user276603 Jun 28 '17 at 14:25
  • 1
    If you only have getters for those fields, then you are achieving encapsulation as they are only publicly readable. It's only an issue if you provide getters and setters for those private fields. – David Arno Jun 28 '17 at 15:01
  • @DavidArno - Suppose you favor immutable classes, so no setters, but you have 3 private string variables and you provide getters for those 3 variables to display in a GUI, that would be fine, correct? You're not breaking encapsulation? – user276603 Jun 28 '17 at 15:37
  • In principle, those three getters sound fine. But without seeing the code, it's hard to say absolutely. I'd refer you to @PeteKirkham's excellent answer below, which addresses this and more. – David Arno Jun 28 '17 at 16:32
7

Firstly, you have to consider why we encapsulate state. This stock answer is fairly typical:

Encapsulation makes it possible to separate an objects implementation from its behavior to restrict access to its internal data. This restriction allows certain details of an object's behavior to be hidden. It allows us to create a “black box” and protects an object's internal state from corruption by its clients.

Note that a well written set of getters will not expose an object's internal state to corruption by its clients. ( You have to remember to return immutable copies or views of any collections or mutable objects referenced by your getters to be sure that the client cannot change the state of your object through them, this can have some cost if you can't do that without copying data. )

Secondly, when looking at answers similar to the one you referenced, yes you can do that. It does encapsulate the data, and puts everything about the data in one place. But it does so at a cost of increased coupling, and that approach means the responsibility of the class is massively increased - not only does it maintain the state of an entity, it also creates graphics controls for all operations in the UI which the entity may be involved in.

Modern software goes beyond the simple OO paradigm including reflection used for serialisation and persistence, and scripting languages used for APIs and report generation. So the SOLID principles of single responsibility ( the entity class' only job is to maintain consistent state ) and open/closed ( an extension of the application by adding another view of the entity does not require changing the entity class' code ) are often better met by providing getters than by moving all possible functionality into the one class.

The argument against splitting the responsibility of display, serialisation, reporting out from maintaining entity consistency is mainly YAGNI. Sometimes this is true. The current application which I am working on deals with 'channels' of time series data; the properties of the channel are in around thirty different UI screens or reports, not to mention the Python scripts the users create using the API to access the properties. Having to put all those features into the one class, especially the reports which require matching data from various collections of entities, would not make sense. That would be way too much responsibility for one object.

As far as setters go, that is more tricky. I tend to create applications as pipelines of transformations working against read-only interfaces; transformations creating reports or views of the entities, and also transformations passed into the back-end to cause a change to the persistent state of the entities. To update a persistent entity, rather than mutating it directly, you send the changes to the repository together with your credentials, where the changes are applied to a mutable implementation of the interface, all constraints are validated by that implementation, the persistent state updated and the update logged for auditing. That removes quite a lot of the problems, but not all of them, and is rather specialised to applications where knowing which of many users has updated something is important.

  • So, I tend to favor immutable classes, which means no setters, let's say I have a class like Author and I provide getters only for the first and lastname (assuming that those are the only two private variables), I still won't be breaking encapsulation, correct? – user276603 Jun 28 '17 at 15:39
  • That depends on the definition of encapsulation that you favour - strictly, it would, but it does not lead to one of the issues that encapsulation is used to prevent. Encapsulation is a technique, not a goal in itself, and breaking it is usually less worse than run-away coupling. – Pete Kirkham Jun 28 '17 at 15:59
  • AH! I see. My defination is that getters/setter don't break encapsulation, they enforce, but given that I favor immutable classes, it's just getters that I use to display my data in a GUI, but, there are numerous ways this can be done, so in this case getters are okay? – user276603 Jun 28 '17 at 16:03
4

Restricting write access to an internal variable but granting read access does not preserve encapsulation, as external code can then depend on the objects internal state just as much as any of its methods would.

Having getters for all of a class's member variables should be a warning sign that something is wrong.

Instead, you should have something like a generateDisplayInformation() method, which either collects all relevant information and returns it in some data structure (think an array indexed by an enum, a struct, or a methodless class), or takes in some interface it writes the information to (like an ostream). This allows the class to store data internally however it wants, and not worry about state.

Also, by having the gathering of information occur in a single method of the class, you can always provide a valid snapshot of the information in multithreaded codes (which most GUI applications are).

You should prefer classes providing functionality rather than data access. It doesn't mean you should not have methods like getName() — it just means you should think it through.

  • The 1st sentence - Gold. And it generally contradicts, from the other answer: "... a well written set of getters will not expose an object's internal state to corruption by its clients." Exposing state risks corruption. As Alan Kay said (paraphrasing), if you're not going through methods you're doing it wrong. Said another way, a well written class hides state and exposes functionality. – radarbob Jun 28 '17 at 18:34
  • Having a read-only interface prevents the object being corrupted- there is no mechanism for changing the state, so how can you corrupt it? Having other functions depend on the properties of the object (but be agnostic to the implementation behind those properties ) is more or less essential if the software does anything useful. Changing that to a push rather than a pull increases the implementation burden on the client and makes the code brittle against additional properties. – Pete Kirkham Jun 28 '17 at 20:48
  • 1
    @PeteKirkham If some external function calls half of the getters, then a method modifies the internal state of the object (either called by the same external function or another thread), and then the rest of the getters are called, a "corrupted" view of the object is retrieved by the function. – dlasalle Jun 28 '17 at 21:14
  • @dlasalle yes, in general. In my answer the changes only occur in discrete transformations, the visible state of any given instance does not change - the only changes are internal, such as lazily populating collections. So they behave in practice closer to how the result of your proposed generateDisplayInformation() would. The object has a read-only interface, any change to its internal state is not visible in the state of its externally visible properties . – Pete Kirkham Jun 29 '17 at 8:05
1

My question is for those developers that agree that getters/setters break encapsulation and should be avoided.

Consider Wikipedia's description of Encapsulation:

  • A language mechanism for restricting direct access to some of the object's components.
  • A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.

Based on this, perhaps a more useful soundbite for Encapsulation would be Implementation Hiding. Getters and Setters are generally used for accessing and mutating data (hence the more formal names for them as accessors and mutators), but not all data is necessarily part of a class' implementation, and not all of a class' implementation will necessarily be data (for example, a class may include a private method which internally modifies its state)

For example, consider a TcpSocket class which supports reading and writing data packets via a network. Such a class may expose a pair of get/set methods for configuring the socket's timeout duration - something which most programmers would reasonably assume they should be able to control. I don't think any reasonable programmer would argue that a pair of get/set methods to control these kinds of configurable parameters risks exposing the class' implementation.


  1. How do you display your data in a GUI if necessary without getters? I found this link, but to me it seems kind of strange for your class to be aware of components to display.

Typically I would separate the GUI away from those classes which represent core application logic and/or business logic. In general, I tend to keep a clear distinction between GUI components (i.e. the View components which are responsible for appearance, layout, presentation of data and user interactivity) away from behavioural classes (which are responsible for an application's real functionality) as far as reasonably possible.

I prefer to use an MV* pattern (MVC/MVP/MVVM/etc.) to expose data to GUI Views using View Model classes which are composed entirely of 'plain' data fields, containing no behaviour or methods (or at least, as little behaviour as reasonably possible). Those types of classes typically don't even need getters/setters, because their purpose is to serve as simple data classes, and do not form part of any implementation detail for your business logic (so they don't break encapsulation for anything either).

With this kind of separation between GUI code and Application/Business logic, there are plenty of options for how to extract a ViewModel without polluting your Business logic classes with dozens of unnecessary get/set methods; in fact, you might not even need the GUI to talk directly to your business logic at all, the GUI might just talk to a Web Service or Database to get the View data instead.


What if you designed a class where all the properties have getters for displaying, now I understand someone could call the getters and use them for calculations and behaviors other than displaying, but my point is, if you find it nessesary to provide getters for all your private variables to display, should you be rethinking your design? if so, how?

This type of design sounds to me like a symptom of insufficient separation between GUI/presentation logic and the core business or application logic. As mentioned above in the paragraph about MV* patterns, I would fundamentally rethink the design by providing a way to pull a copy of the relevant data out of the class into a separate data model, which can be pushed into the view. One of the most important reasons for doing this is to allow the data to be freely modified by the GUI without instantly reflecting that change back into the core business logic.

On the flipside, if the GUI needs to push data back in to the business logic, then perhaps the business class needs to be able to receive a copy of that data and update itself.

On the note about working with copies of data; This could be for a whole range of reasons. For example, there may be validation steps involved, or the user might want to be able to hit a 'Cancel' or 'Undo' button to throw away their changes too. Typically I wouldn't allow a user to make changes to the state of an application until they've issued some kind of active 'Save' or 'Commit' type command (e.g. 'File -> Save', 'OK', etc.)

0

This answer is largely a reframing of dlasalle's which I recommend.

Displaying data to the UI doesn't require setters, so the problem is restricted to getters. Further, ignoring debugging, if you are trying to display some data in the UI, it presumably is "public" data. If you are trying to display this data, then it is part of your object's specification and therefore can't be private implementation details. If you are trying to display data derived from this private data, then you should only expose that derived data. So, I'm going to assume the suggestion is to only make getters for data that is "public" in this sense.

If I want an object to be able to present itself, then I should make a method to do that. This is what dlasalle means with: "You should prefer classes providing functionality rather than data access." It's neither necessary nor sufficient to instead provide a bunch of getters. It's not necessary because a) I clearly only need to add one method to return some sort of "presentation object", and b) that presentation object may itself not provide any access to the specific fields (though it likely will for flexibility), e.g. it could have a method that takes a "UI builder object" and use that to produce a UI. It's not sufficient because, as dlasalle brilliantly points out, there's no guarantee that invoking a series of getters will give you a coherent picture of the object's state. This is especially true in a concurrent context, but it is true even in a sequential context. Again, if one of the responsibilities of an object is to provide a coherent snapshot its state, then this needs to be an explicit method that provides such a guarantee. (For example, imagine if accessing a field required a database look-up. If I access each field in a separate database transaction, then I lose atomicity and isolation guarantees.)

The analogies of the object providing a snapshot of its state / providing a report / providing a serialization of its state are suggestive. It suggests that the "presentation object" the method produces should be an immutable object. This object should conceptually consist only of "pure data", i.e. it should be a value object. If you'd like the UI to change as the original object changes, then the object should publish a stream of "presentation objects" (perhaps using something like ReactiveX).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy