16

Possible Duplicate:
When are Getters and Setters Justified

In an Object oriented framework, one believes there must be strict encapsulation. Hence, internal variables are not to be exposed to outside applications.

But in many codebases, we see tons of get/set methods which essentially open a formal window to modify internal variables that were originally intended to be strictly prohibited. Isn't it a clear violation of encapsulation? How broadly such a practice is seen and what to do about it?

EDIT:

I have seen some discussions where there are two opinions in extreme: on one hand people believe that because get/set interface is used to modify any parameter, it does qualifies not be violating encapsulation. On the other hand, there are people who believe it is does violate.

Here is my point. Take a case of UDP server, with methods - get_URL(), set_URL(). The URL (to listen to) property is quite a parameter that application needs to be supplied and modified. However, in the same case, if the property like get_byte_buffer_length() and set_byte_buffer_length(), clearly points to values which are quite internal. Won't it imply that it does violate the encapsulation? In fact, even get_byte_buffer_length() which otherwise doesn't modify the object, still misses the point of encapsulation, because, certainly there is an App which knows i have an internal buffer! Tomorrow, if the internal buffer is replaced by something like a packet_list the method goes dysfunctional.

Is there a universal yes/no towards get set method? Is there any strong guideline that tell programmers (specially the junior ones) as to when does it violate encapsulation and when does it not?

Dipan Mehta
  • 10,542
  • 2
  • 33
  • 67
  • 2
    Instead of religiously regarding encapsulation as a kind of commandment, it's better to understand why it's important. Encapsulation is a means to hiding information. That is an old concept that applies to lots of system design (not just OO). It's better to hide details because 1) it make things simpler to the outside, 2) any details that are hidden to the outside can be changed without a negative impact on the outside. So, when a get or set reveals or provides access to information that should be hidden, you're making your design more complex/fragile. There is no `universal yes/no` answer. – Fuhrmanator Jul 24 '14 at 03:32

6 Answers6

26

No.

Getters and setters don't violate encapsulation, they provide it. If you're using accessor methods, you are by definition not accessing an object's variables directly. You are instead using an interface that the object provides to manipulate some properties, and you don't care whether those properties are stored in ivars, stored in a dictionary, calculated from other values, etc. The implementor of the class in question remains free to change the way the class works without breaking existing client code so long as he or she maintains the interface.

Some say that if your interface consists of little more than a set of accessors for your instance variables, your class isn't doing enough to justify its existence, or you're not doing enough to hide the way the class works from external code. All that may be true, depending on the class, but it doesn't change the fact that access to the internal state (the ivars) is restricted to the class' own methods and therefore encapsulated.

There's obviously some disagreement in the comments below about what the term encapsulation means. I offer the following definition from the paper Encapsulation and Inheritance in Object-Oriented Programming Languages (pdf):

A module is encapsulated if clients are restricted by the definition of the programming language to access the module only via its defined external interface. Encapsulation thus assures designers that compatible changes can be made safely, which facilitates program evolution and maintenance. These benefits are especially important for large systems and long-lived data.

It's hard to argue that accessors don't qualify as "defined external interface" to a class. If you also take steps to prevent external direct access to a class' internal state (that is, make your ivars 'private'), then by the definition above you will have achieved encapsulation.

From a pragmatic viewpoint, though, things aren't exactly that simple. The very next paragraph in the paper goes on to say:

To maximize the advantages of encapsulation, one should minimize the exposure of implementation details in external interfaces. A programming language supports encapsulation to the degree that it allows minimal external interfaces to be defined and enforced.

Like any technique, encapsulation can be used well or not so well, and I think this is at the heart of most differences in opinion about what does or doesn't "break" encapsulation. If hiding the internal representation of data behind an external interface is good, then revealing only what is necessary for the class to do its job is better. A class which has a one-to-one correspondence between property accessors and ivars can properly be said to encapsulate its state, but it may not be using that encapsulation to best effect. I'd agree that if your code contains many classes in this situation, it's a good bet that the system is not as well designed as it could be.

How can you judge whether you're using encapsulation effectively? Continuing from the paper:

This support can be characterized by the kinds of changes that can safely be made to the implementation of a module. For example, one characteristic of an object-oriented language is whether it permits a designer to define a class such that its instance variables can be renamed without affecting clients.

I like this test because it provides a simple guideline that corresponds directly to the reason we value encapsulation in the first place. It also makes clear the idea that the benefit gained from encapsulation is a continuous value, not a binary one. We shouldn't lose sight of the fact that the paper describes encapsulation as a language feature, but I think it's safe to apply the test to specific code to help us decide how well that code uses the encapsulation provided by the language.

Example 1: Applying the "What kind of changes can safely be made?" test to the example in the OP's question, it seems likely that the code probably doesn't make good use of encapsulation. It may be technically true that the get_byte_buffer_length() and set_byte_buffer_length() methods encapsulate some internal state, but if the "byte buffer" is an implementation detail rather than an important external property of the UDP server, the buffer shouldn't be exposed at all. The very fact that it is exposed limits the ways in which the UDP server can be modified.

Example 2: It's often said that inheritance breaks encapsulation because subclasses typically (depending on the language) have direct access to the parent class' internal state. Despite this, programmers can take advantage of encapsulation by using accessors (sometimes private accessors) to access state from a parent class instead of using the ivar itself.

When in doubt, a programmer should ask him or herself: Will my code break if the parent class changes? and Will subclasses of this class break if I change X?

Caleb
  • 38,959
  • 8
  • 94
  • 152
  • 22
    Getters provide access to an object's state. By definition they break encapsulation... albeit in a controlled/mediated manner. Setters are even worse. – Frank Shearar Nov 21 '11 at 08:17
  • 7
    @Frank Shearar: "Getters provide access to an object's state." They do this in a way that is known to provider. And actually if you don't have access to provider's code, how do you know that getters/setters expose actual state? – Den Nov 21 '11 at 10:15
  • 2
    On the other hand they _can_ violate encapsulation, if mutability is not handled correctly. – Den Nov 21 '11 at 10:16
  • 6
    @Frank -- so if I have a "customer" object "getZipCode" would break encapsulation? Objects are there to perform useful function, if the functional requirement to to provide a ZIP code then a "get" method is the only way to do it. If the functional requirement is to allow the caller to set the ZIP code how else would you implement this other than a "set" method? – James Anderson Nov 21 '11 at 10:30
  • 5
    @James: "Tell, don't ask." But my point is that getters are not a means of encapsulation, since they expose state. – Frank Shearar Nov 21 '11 at 10:34
  • 3
    @FrankShearar so? Some objects that exist may need to have their states exposed. Since one shouldn't expose them directly, instead of members you would want a method that exposes them. That's what a getter is, how else can you expose something that needs exposing? Why don't you want objects interacting with each other? – StuperUser Nov 21 '11 at 11:48
  • 8
    @StuperUser If that object needs to expose its state, then do so. But don't pretend that you're _not_ exposing state just because you wrapped your field in a getter. – Frank Shearar Nov 21 '11 at 12:13
  • 6
    @FrankShearar Accessors turn ivars into properties. I might write a Color class with setters for red, green, and blue. Maybe I have ivars for red, green, and blue, or maybe I don't -- perhaps my class uses a CMYB or HSV color model internally. The client never knows or cares, because the actual state of a Color object is hidden behind an interface. If you don't think that's the definition of encapsulation, I'd be curious to know what you think encapsulation is. – Caleb Nov 21 '11 at 13:24
  • 4
    @Caleb: I know exactly what getters/setters are and do. You are taking an otherwise perfectly black box, and poking holes in it. There is no semantic difference between exposing a field and an autogenerated C# getter a la `public int Foo {get; set;}`. (There is an important difference in that the latter is _mediated_, _controlled_ access which allows you to alter said control at a later stage without touching the callers. It's still access.) – Frank Shearar Nov 21 '11 at 14:55
  • 2
    Encapsulation does not imply you have or want a "perfectly black box", because the only "perfectly black box" is `class X {}`. – Random832 Nov 21 '11 at 15:02
  • 2
    @Caleb: I disagree with you. In general, I'd say that getters/setters DO break encapsulation. Public methods that do not perform one of the "use cases" of the domain object -- its responsibility -- are a case of encapsulation breakage. Sometimes it's a necessary evil, but it is a form a breakage nonetheless. In the case of the original poster, if he is finding "tons of get/set methods" in his codebase, I'd say that's a code smell. – Andres F. Nov 21 '11 at 15:10
  • I thought some more and found another reason to be suspicious of excessive getters/setters: if you need to have "tons" of them in your code, it's likely your domain is anemic. Your objects are probably just beans which expose their state for other parts of your system to do the actual work. This isn't black or white, of course, but at least it's a code smell. – Andres F. Nov 21 '11 at 15:23
  • @FrankShearar, Andres F.: I've expanded my answer significantly to try to incorporate what I think is your view of encapsulation. I'd be happy to have your comments. – Caleb Nov 21 '11 at 18:56
  • 1
    @Caleb: I rather like it! I'm not trying to take a dogmatic Thou Shalt Not Use Getters/Setters - I'm suggesting that they're things one should use with caution. – Frank Shearar Nov 21 '11 at 20:16
  • 1
    It's not complicated. Vanilla getters/setters granting access to mutable properties are no more encapsulation than exposing public properties. !@#$ disagreement. It's not encapsulation or you don't understand the whole point. And for the record I AM taking a dogmatic Thou Shalt Not Use Getters/Setters. It's stupid and you don't understand OOP if you do it regularly. Not at all. !@#$ DTOs. !@#$ beans. Try to live without and see what happens. You'll get OOP, maybe for the first time in your career if you just try it. Tell, don't ask. – Erik Reppen Jun 22 '13 at 06:05
  • 1
    @ErikReppen How do you get the velocity of a spaceship? Answer: you use the `velocity` accessor. Does that method simply return the value of the `_velocity` ivar, or does it calculate velocity from speed and direction values, or something else? As the client, you don't know and you don't care. *That* is encapsulation, no matter what the method actually does. Accessing the `_velocity` ivar directly breaks encapsulation -- it relies on knowledge of the spaceship's implementation and makes it impossible to change the implementation without breaking client code. – Caleb Jun 22 '13 at 14:40
  • @Caleb Ouch. Stepped on that rake. Okay, so I WON'T get dogmatic about getters, but I will about setters, and I definitely will about user-defined classes operating strictly as dumb data objects. – Erik Reppen Jun 22 '13 at 16:44
  • 1
    @ErikReppen So... How do you set the velocity of a spaceship? – Caleb Jun 23 '13 at 03:00
  • @Caleb Event listeners/observers. It knows its rate of acceleration. It knows how it would respond to changing circumstances and what its priorities are. It sets the vector/direction + velocity based on something nothing else needs to know, which is what it's actually capable of. But yeah, it does need to check all the other vectors of objects in the environment to know it is or isn't about to collide with something and that requires a getter. And that's where I realized I was being a chump. It might make sense to have something else managing collision but that still requires getters. – Erik Reppen Jun 23 '13 at 04:58
  • 2
    @Caleb you probably DON'T want to allow people to set the velocity of your space ship. If anything, a space ship should have some sort of navigation interface that lets you accelerate, plot a course etc. consider a car. you don't tell the car "acquire a velocity of 30 m/s". you push the gas pedal, change the gears, turn the wheel etc. a lot of the time getters aren't needed either. if all you do with a getter is to inspect it, and then do some action with the object based on the value, you are not following OOP principles. sometimes properties are needed, but they always break encapsulation. – sara Mar 18 '16 at 12:04
  • 1
    @kai You assume far too much about my simple example. If you're writing a spaceship flight simulator, sure, you don't let the pilot directly set the spaceship velocity; if you're writing the control system for a game, it might be useful to be able to insert a ship and set it's velocity instantaneously. Or maybe you do let the pilot call `setVelocity`, but that method takes physics into account and it takes time for `velocity` to reach the set value. That proves the point about accessors: just because they're there doesn't mean that you're directly changing the object's state. – Caleb Mar 18 '16 at 13:21
  • @Caleb "How do you get the velocity of a spaceship ?" You don't, that's the point. You tell it to accelerate or whatever it needs to do. A better question might be what if we have an space ship operator that needs to control all space ships to see if they are about to collide with each other. There are multiple ways to go about this, you could share encapsulation with that controller in some languages where it is supported. Effectively widening the scope. Or you could use the fact that each spaceship is a spaceships, so they can access properties of other spaceship, namely the velocity. – Ced Oct 24 '22 at 19:35
  • @Ced So how do you draw the spaceship's speedometer? How do you predict when the spaceship will arrive at its destination? The point I'm making in the example (IIRC -- I wrote that comment 6 years ago!) is that `velocity` is part of the spaceship's interface. A client has no idea *how* the result of the accessor does what it does -- maybe it reads an ivar, or maybe it calculates the value from other info, or maybe it reports values directly from sensors. Moreover, Spaceship v2.0 may get that info entirely differently, and I don't need to care. That's the definition of encapsulation. – Caleb Oct 24 '22 at 20:57
  • @Caleb That is not the only definition of encapsulation, you are talking about encapsulation towards change. A deeper encapsulation is having private fields, which is abstraction. Once you leak details, it has to spread outside the object. To answer you question the object knows how to display itself, in fact they already do with the `toString()`. It does not mean the object has to know about the details of the display implementation detail though, it could be `display(Display display)`. I know this idea seems alien, and it was alien to me a month ago but there is something to it, imo – Ced Oct 24 '22 at 23:15
  • Here is an article that explains some of it https://javadevguy.wordpress.com/2019/06/06/data-boundaries-are-the-root-cause-of-maintenance-problems/ – Ced Oct 24 '22 at 23:28
  • @Ced I’m sure you’re not suggesting implementing an entire spaceship as a single monolithic class? That’d defeat the point of OOP. But let’s not take this further — comments are for clarification, and I don’t think we need that on a 6yo comment to an 11yo question that’s been closed for 10. Consider reading the nuanced accepted answer on the duplicate. – Caleb Oct 24 '22 at 23:55
12

They can be: As noted in other answers getters/setters by definition provide some encapsulation of the field within the object. There are some pitfalls however. The pseudo code below for instance allows client code to mess about with the internals of the objects of type Foo, because the list 'bars' is a mutable object, so client can do anything to - like clearing it or adding new stuff to. This in my view is a clear violation of encapsulation.

class Foo
{
    private List bars = new List();

    public List GetBars() 
    {
        return bars;
    }
}

To alleviate this either don't provide the getter for bars at all or have it return a readonly copy of the list:

class Foo
{
    private List bars = new List();

    public List GetBars() 
    {
        return bars.AsReadOnly();
    }
}

This problem is not specific to lists, but can turn up with any mutable complex type returned from a getter.

Christian Horsdal
  • 1,499
  • 10
  • 10
9

I generally try to avoid public setters - if data needs to be provided to an object it ought to go in via method parameters or the constructor. By setting a property externally you are potentially undermining the integrity of that object.

Encapsulation is more about the semantics of the public API that the object exposes...

Take a simple class with a Name property:

public class Foo
{
    public String Name { get; set; }
}

I would prefer to write this as (given this is a very simple example):

public class Foo
{
    public String Name { get; private set; }

    public void Rename(String name)
    {
        this.Name = name;
    }
}

The goal here is that you're not directly modifying the state of the object from the outside... you're invoking some piece of behaviour, and it's that behaviour which has an observable effect on the objects internal state.

This pattern can be enhanced further with immutability:

public class Foo
{
    // Clone constructor...
    private Foo(foo prototype) { ... }

    public String Name { get; private set; }

    public Foo Rename(String name)
    {
        return new Foo(this)
        {
            Name = name
        };
    }
}
MattDavey
  • 7,096
  • 3
  • 31
  • 32
  • 2
    It's not clear what the difference between allowing someone to call Rename and allowing someone to call a setter on Name is. And you've still got a getter, which the question proposes may also be a violation of encapsulation. – Random832 Nov 21 '11 at 15:12
  • @Random832 agreed this contrived example does not clearly show the benefit. The difference is in semantics. A method called Rename clearly denotes **behaviour**. Going back to the basics of OOP, *"an object comprises state and behaviour"*. Behaviour being what you can poke, and state being what you can peek. Get/set properties blur this boundary somewhat. – MattDavey Nov 21 '11 at 15:25
  • The other advantage of course is that in many languages a setter can't return a value, which would mean my example with immitability wouldn't work.. – MattDavey Nov 21 '11 at 15:30
  • Well, right, but replacing the first rename method with the second would silently break calling code. Replacing a setter with a method would at least _noisily_ break calling code. – Random832 Nov 21 '11 at 15:48
  • @Random832 changing an object from mutable to immutable would be a major change to the API and should be treated accordingly, but that's pretty off topic for this question. – MattDavey Nov 21 '11 at 16:03
3

They can be! The example you provide seems to be a good example where they are. Such methods provide access on a very low level of abstraction, and don't encapsulate the user of the class from the details. That does not mean that a class like this is wrong or bad, it depends on the intended usage.

The Server in your example would IMO be much better take a buffer policy (at construction with a reasonable default, like dynamic buffer) so that it can answer read or send requests without the user caring or even knowing about the details of the buffer management if sHe doesn't want to.

Fabio Fracassi
  • 926
  • 8
  • 8
1

Suppose you have a 'Complex' class. It has four getters: real, imaginary, magnitude, and angle. Clearly, in any reasonable representation, two of these functions simply return the value of a private member variable. What encapsulation means is that it doesn't matter which two of these methods is "simple" and which one does a calculation.

(one could imagine a mutable complex class that also has setters for these. Again, clearly two of them simply directly set a private member variable.)

Random832
  • 167
  • 1
  • 3
0

In my opinion, as long as you allow the property to change from within your class code and using your class code, you are not violating encapsulation.

If you want to prevent change, there are ways to prevent change either at design time (using access modifiers, readonly specification) or at run-time (using business rules).

One of the advantages of using set/get pair is to provide a point in your code to control what happens after/before reading/setting a data value.

we see tons of get/set methods which essentially open a formal window to modify internal variables that were originally intended to be strictly prohibited.

Regarding internal variables (I assume you are taking about fields as in C#), those are always recommended to be declared private whether the property is public, read-only, or otherwise.

This link may add further help: Using a SetProperty method to prevent accidental changes to a property

Edit-1

After reading your edit to the original question

Based on your example, the problem is not with get/set per-se. I think that the implementation of properties that depend on external source of data leads to the dependency problem you are describing. To have a more 'pure' property definition, you should send a message to the object owning this data and let the method return the desired value, then use Set/Get to continue processing.

Encapsulation definition (as in Encpc.Def-About.Com does not imply that the data of a class must all be created in the class or by the class alone. It is OK (and in fact desirable) for classes to communicate or collaborate. This way, you limit the complexity of a class and encourage sharing of code that already exists.

Edit-2

This in response to the first comment for the message. Reading Martin Fowler in this article Getters Eradicator says:

"I have a lot of sympathy with this motivation, but I fear that just telling people to avoid getters is a rather blunt tool. There are too many times when objects do need to collaborate by exchanging data, which leads to genuine needs for getters."

the article is very related to the subject and may answer your question.

NoChance
  • 12,412
  • 1
  • 22
  • 39
  • I think you are focusing too much on how to restrict the modification of internal variables. The real issue is that having "tons of get/set methods" not only breaks encapsulation but is also a form of high coupling. Even when having just getters! Why on Earth do your classes have "tons of getters"? What is their main responsibility? It seems like it could easily lead to an anemic domain model, with other parts of the system using your getters to do the actual work! Seems contrary to OOP... – Andres F. Nov 21 '11 at 15:19
  • Thanks for your comment, I have add a link under Edit-2, that may be of help. – NoChance Nov 21 '11 at 18:16