1

Until recently I always had getters (and sometimes setters but not always) for all the fields in my class. It was my 'default': very automatic and I never doubted it. However recently some discussions on this site made me realize maybe it's not the best approach.

When you create a class, you often don't know exactly how it's going to be used in the future by other classes.

So in that sense, it's good to have getters and setter for all of the fields in the class. So other classes could use it in the future any way they want. Allowing this flexibility doesn't require you to over engineer anything, only to provide getters.

However some would say it's better to limit the access to a class, and only allow access to certain fields, while other fields stay completely private.

What is your 'default' approach when building a class from scratch? Do you make getters for all the fields? Or do you always choose selectively which fields to expose through a getter and which to keep completely private?

  • 1
    YAGNI – user40980 May 29 '14 at 23:41
8

That really depends on the purpose of the class. If it's a "struct" class that just bundles data together, then it should expose all of its fields since it only keeps them, not using them. Classes that have actual behavior should usually be more restrictive in providing access to their inner state.

Always exposing the internal structure "So other classes could use it in the future any way they want" violates the very core of OOP. The class should be the one who defines how to use its internal structure, and provide an interface (methods) for doing so.

Take for example a C++ array-with-length (I haven't written C++ in a long time, so forgive any syntax errors):

class Array{
    private:
        int* array;
        size_t length;
    public:
        Array(size_t length):length(length){
            array=new int[length];
        }

        size_t getLength(){
            return length;
        }
        void setLength(size_t length){
            this.length=length;
        }

        int* getArray(){
            return array;
        }
        void setArray(int* array){
            this.array=array;
        }
}

This class is so wrong that this answer might get flagged as offensive. It exposes the internal state - array and length - so other classes will be able to use my class any way they want. For example, if some code somewhere else wants to set the length to be different than the amount of memory (times sizeof(int)) allocated to array, they'll be able to do it!

My class shouldn't let others play freely with its internal state. Instead, it should provide an interface for modifying that state in a way that keeps it stable.

  • 3
    +1 for "This class is so wrong that this answer might get flagged as offensive." – Mike E May 30 '14 at 5:41
  • "Always exposing the internal structure (...) violates the very core of OOP": that should be the first, and possibly the only, sentence of this answer. – logc May 30 '14 at 12:21
  • 4
    @logc Until the cargo cult preacher license card that I ordered from eBay arrives, I'm gonna keep my habit of explaining why things are wrong instead of just saying they are wrong. – Idan Arye May 30 '14 at 14:38
  • Thanks for answering. Although what you're saying is helpful, it doesn't really answer my question clearly. Let me present it in a different way: when building a class - do you usually have getters (not setters) for all fields? Or do you put thought specifically into each variable, if to expose it through a getter or not - resulting in some fields having getters and some don't? – Aviv Cohn May 31 '14 at 17:08
4

Expose properties and methods that are going to be part of the public API of the class, or which fulfill an interface contract.

You should be thinking about your class's API from the start, not based on what you intend to expose publicly, but instead what functionality your class is going to provide.

  • Let me ask a more specific question: when building a class - do you usually have getters (not setters) for all the fields? Or do you think for each variable whether it needs a getter or not, resulting in some variables having getters and some don't? – Aviv Cohn May 31 '14 at 17:12
  • (I understand what you're saying, but still I'm trying to come to a conclusion regarding this specific dilemma, since it does seem that a lot of programmers have getters for all fields 'by default'). – Aviv Cohn May 31 '14 at 17:13
  • Note the clarifications that Telastyn made in his answer. He talks about immutability, which is a very important consideration, and he also talks about Data Transfer Objects, which are basically containers for data, without any behavior. DTO's are going to be basically property bags with getters for all fields, but they have a specific purpose (passing data around), so they don't follow the rules of "ordinary" class design. – Robert Harvey May 31 '14 at 19:29
1

I tend to follow Robert Harvey's answer (focus on the functionality of the class, not the bits to do that), but there's some more to it than that.

It is rare that you're ever making one class from scratch. You're often providing some set of functionality, and a key decision to make is where to draw the lines to break that set of functionality into class-sized chunks. What's a class sized chunk? A single responsibility.

Personally, I find it effective to draw those lines of separation so that the individual classes provide a good API, but also differ in how mutable they are. Especially as programs become more concurrent and more complex, immutable objects allow your implementation to be simpler, more robust and more bugfree.

So in reference to the question, "by default" I aim to make my classes immutable when possible. They take what they need in the constructor and expose the functionality that is that class' responsibility. After that, I aim to make mutable objects have a default constructor and a sane initial state.

Once I'm on to mutable objects it depends on what the object does. Some objects are a set of functionality where the user can manipulate a state, but not necessarily data. Think of the progression of a game of poker. The poker game here is mutable because its state can progress. For these objects, "by default" I will go with conventional encapsulation. The state (who has what cards, who is the dealer, what the pot is) is hidden and the functionality (deal cards, bet, raise, etc.) is exposed.

Some objects are just data. Think of a contact in your email app. Here, the purpose of the object is just to bundle the name, email address, phone number, etc. together so the user can edit them. Having that publically mutable data is the responsibility of the object, so just make the stuff public. Languages with properties make this easier, but there should be little functionality in these sorts of classes (again, "by default").

  • What do you mean by 'conventional encapsulation'? Could you give an example 'poker game' class to demonstrate? – Aviv Cohn May 30 '14 at 8:35
0

Unless your class is Plain Old Data, start by defining the interface its clients will see. This is a PITA in C++, not so bad in Java. Program to the interface; hide the class - if need be - behind a factory object.

Thus you can distinguish between changes you make to the class that don't affect its clients (these change the class but not the interface) and those that do affect the clients (these change the interface).

An intelligent linker (such as Component Pascal/Black Box possessed) should enable you to avoid rebuilding clients in the former case. I have no idea whether Java does this. You can do this in C++, but you have to be careful how you arrange and use your header files.

0

What is your 'default' approach when building a class from scratch? Do you make getters for all the fields? Or do you always choose selectively which fields to expose through a getter and which to keep completely private?

Getters and setters are a sign of a deeper problem, that being that the programmer is focused on the data the class holds, not the behaviour it encapsulates.

The "default" approach should be to not be thinking about the internal data of the object in the first place at all. If you don't start off by defining internal variables then there are no variables to worry about exposing in through getters or setters.

Be thinking instead of the behaviour the object is attempting to represent in the model. Expose that behaviour through methods with meaningful names. Only then think about how the object is going to carry this behaviour and if it needs any private variables to do this (it may not)

My default steps -

  1. Think what in the business domain this object is representing and define a class.

  2. Think of the first behaviour this object is responsible for, and define a method that exposes this behaviour to the outside world.

  3. Work out how to carry out this behaviour, what internal variables you need (if any).

  4. Either finish the class (nothing wrong with an object with only one method) or if there are closely related behaviour define another public method.

  5. Refactor if necessary (you might find that the class if growing too big, so you split it off).

99.9% of the time after you have done that you will have no internal variables left over to even consider a getter or setter for.

  • Thanks for your answer. So what you're saying is: start with thinking what functionality this class needs to offer to the outside world, and define methods for that. I.e. start with thinking about the interface. If this functionality requires the class to have some getters and/or setters, okay. Otherwise, they're unnecessary. Right? – Aviv Cohn May 31 '14 at 2:09

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.