Getters and Setters Are Bad Oo Design

Getters and Setters are bad OO design?

Getters or setters by themselves are not bad OO design.

What is bad is coding practice which includes a getter AND a setter for EVERY single member automatically, whether that getter/setter is needed or not (coupled with making members public which should not be public) - because this basically exposes class's implementation to outside world violating the information hiding/abstraction. Sometimes this is done automatically by IDE, which means such practice is significantly more widespread than it's hoped for.

Are getters and setters poor design? Contradictory advice seen

There is also the point of view that most of the time, using setters still breaks encapsulation by allowing you to set values that are meaningless. As a very obvious example, if you have a score counter on the game that only ever goes up, instead of

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

it should be

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

This is perhaps a bit of a facile example. What I'm trying to say is that discussing getter/setters vs public fields often obscures bigger problems with objects manipulating each others' internal state in an intimate manner and hence being too closely coupled.

The idea is to make methods that directly do things you want to do. An example would be how to set enemies' "alive" status. You might be tempted to have a setAlive(boolean alive) method. Instead you should have:

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

The reason for this is that if you change the implementation that things no longer have an "alive" boolean but rather a "hit points" value, you can change that around without breaking the contract of the two methods you wrote earlier:

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }

Correct OOP design without getters?

Allen Holub made a big splash with "Why getter and setter methods are evil" back in 2003.

It's great that you've found and read the article. I admire anybody who's learning and thinking critically about what they're doing.

But take Mr. Holub with a grain of salt.

This is one view that got a lot of attention for its extreme position and the use of the word "evil", but it hasn't set the world on fire or been generally accepted as dogma.

Look at C#: they actually added syntactic sugar to the language to make get/set operations easier to write. Either this confirms someone's view of Microsoft as an evil empire or contradicts Mr. Holub's statement.

The fact is that people write objects so that clients can manipulate state. It doesn't mean that every object written that way is wrong, evil, or unworkable.

The extreme view is not practical.

OOP Should all properties have getters and setters

Getter and setter should be always used. The reason of getter or setter is not to provide a public interface to internal properties, rather to provide a control over read/write of a property. They provide abstraction over the class properties.

Even your class properties is private you need getter and setter. This allows to control the value just before assigning or reading.

Think about a class you designed long ago where you do some common calculation for each read.

class A{
private decimal x;
public void do_stuff(){
decimal a = this.x/70;
// process with a
}
public void do_anoter_stuff(){
decimal a = this.x/70;
// process again a
}
}

Now you want to change the factor (70). how do you do it? change it in every place? Better design it this way.

class A{
private decimal x;
private get_x(){ return this.x/70; }
public void do_stuff(){
// process with get_x()
}
public void do_anoter_stuff(){
// process again get_x()
}
}

The fact is blindly using getter and setters for every property is evil. The rule of thumb is. Declare all properties as private with private getter and setter. Later change the visibility of the getters and setters only to allow access from outer world when needed

Public variables bad practice vs Getters and Setters functions?

First of all, a struct is completely equivalent to a class, but with the default member access being public rather than private.

Now, in Object Oriented Programming (OOP), it's not considered good practice to have public data members (variables), because that makes all your code dependent on the internals of the class, and thus breaking a primordial principle of OOP, and that is...

Holy and Sacred Encapsulation

Encapsulation is the coding philosophy that states that a class should englobe both data and the code that manages it in a single tight entity. That is, you don't access data directy, but rather you use methods from the class to manipulate such data. This has several design advantages, such as that you'll know that no code except the one inside the class may incorporate bugs with respect to the manipulation of such information.

Now, get()ers and set()ers, otherwise known as accessors, are a complete lie! With accessors, you're tricking yourself into thinking that you're respecting encapsulation, when you're rather breaking it! It adds bloat, unnecessary verbosity, bugs, and everything but encapsulation. Instead of having a class Person with unsigned getAge() and void setAge(unsigned), have it with a unsigned getAge() and a void incrementAge() or however you want to call it.

Now, to your question's core...

"Plain old" structs

Encapsulation is not always desired. Although you should (usually) not do this on header files (again, for at least some bit of encapsulation), you may create static plain old structs that are private to a single translation unit. My recommendation is to make them even "older" than they already are, i.e...

  • All data members are public.
  • No methods.
  • No constructors (except implicit ones).
  • Inheritance is always public, and only allowed from other plain old structs.
  • I repeat, don't put them on header files!

Now, another use for plain old structs is (ironically) metaprogrammatic exporting of constexpr data and types, otherwise known as modern-hardcore-template-metaprogramming-without-having-to-type-public-everywhere, for example...

template<bool B, typename T>
struct EnableIf {};

template<typename T>
struct EnableIf<true, T> {
typedef T type;
};

template<bool B, typename T>
using SFINAE = typename EnableIf<B, T>::Type;

Why use getters and setters/accessors?

There are actually many good reasons to consider using accessors rather than directly exposing fields of a class - beyond just the argument of encapsulation and making future changes easier.

Here are the some of the reasons I am aware of:

  • Encapsulation of behavior associated with getting or setting the property - this allows additional functionality (like validation) to be added more easily later.
  • Hiding the internal representation of the property while exposing a property using an alternative representation.
  • Insulating your public interface from change - allowing the public interface to remain constant while the implementation changes without affecting existing consumers.
  • Controlling the lifetime and memory management (disposal) semantics of the property - particularly important in non-managed memory environments (like C++ or Objective-C).
  • Providing a debugging interception point for when a property changes at runtime - debugging when and where a property changed to a particular value can be quite difficult without this in some languages.
  • Improved interoperability with libraries that are designed to operate against property getter/setters - Mocking, Serialization, and WPF come to mind.
  • Allowing inheritors to change the semantics of how the property behaves and is exposed by overriding the getter/setter methods.
  • Allowing the getter/setter to be passed around as lambda expressions rather than values.
  • Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.

Do setter and getter methods breaks encapsulation?

From here:

Having getters and setters does not in itself break encapsulation.
What does break encapsulation is having a getter and a setter for
every data member (every field, in java lingo). That is one step away
from making all data members public.

The point of encapsulation is not that you should not be able to know
or to change the object's state from outside the object, but that you
should have a reasonable policy for doing it.

Consider an example of a class Person. Let's say a person has a name,
a social security number, and an age. Let's say that we do not allow
people to ever change their names or social security numbers. However,
the person's age should be incremented by 1 every year. In this case,
you would provide a constructor that would initialize the name and the
SSN to the given values, and which would initialize the age to 0. You
would also provide a method incrementAge(), which would increase the
age by 1. You would also provide getters for all three. No setters are
required in this case.

In this design you allow the state of the object to be inspected from
outside the class, and you allow it to be changed from outside the
class. However, you do not allow the state to be changed arbitrarily.
There is a policy, which effectively states that the name and the SSN
cannot be changed at all, and that the age can be incremented by 1
year at a time.

Now let's say a person also has a salary. And people can change jobs
at will, which means their salary will also change. To model this
situation we have no other way but to provide a setSalary() method!
Allowing the salary to be changed at will is a perfectly reasonable
policy in this case.

By the way, in your example, I would give the class Fridge the
putCheese() and takeCheese() methods, instead of get_cheese() and
set_cheese(). Then you would still have encapsulation.

You can also refer: Why getter and setter methods are evil



Related Topics



Leave a reply



Submit