質問

I was reading this page, about when getters/setters are justified, and the OP gave the following code sample:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

The accepted answer states:

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.

How is encapsulation preserved by renaming it from get/set to putCheese()/takeCheese() You're obviously getting/setting a value, so why not simply leave it as get/set?

In the same answer it also states:

Having getters and setters does not in itself break encapsulation. What does break encapsulation is automatically adding a getter and a setter for every data member (every field, in java lingo), without giving it any thought.

In this case, we only have one variable, cheese, and you may want to take and return the cheese to the fridge, so a get/set pair in this case is justified.

役に立ちましたか?

解決

I think you are missing the point. Its not saying you should rename the setter and getter, but to have methods which add and remove items from the fridge. ie

public class Fridge
{
    private int numberOfCheeseSlices;

    public void AddCheeseSlices(int n)
    {
         if(n < 0) { 
             throw new Exception("you cant add negative cheese!");
         }
         if(numberOfCheeseSlices + n > this.capacityOfFridge) { 
             throw new Exception("TOO MUCH CHEESE!!");
         }
         ..etc
         this.numberOfCheeseSlices += n;
    }
}

Now the private variable is encapsulated. I cant just set it to anything I want, I can only add and remove cheese slices from the fridge using the methods, which in turn ensure that whatever cheese business logic rules I want are applied.

他のヒント

Getters and setters break encapsulation every single time, by definition. What might be argued is that sometimes we need to do that. With that out of the way, here are my answers:

How is encapsulation preserved by renaming it from get/set to putCheese()/takeCheese() You're obviously getting/setting a value, so why not simply leave it as get/set?

The difference is in semantics, i.e. the meaning of what you write. Encapsulation is not only about protecting, but hiding internal state. Internal state should not even be known outside, instead the object is expected to offer business-relevant methods (sometimes referred to as "behavior") to manipulate/use that state.

So get and set are technical terms and seem to have nothing to do with the "fridge" domain, while put and take might actually make some sense.

However, whether put or take make actual sense still depends on the requirements and can not be objectively judged. See next point:

In this case, we only have one variable, cheese, and you may want to take and return the cheese to the fridge, so a get/set pair in this case is justified.

That can not be objectively determined without more context. Your example contains a go_shopping() method somewhere else. If that is what the Fridge is for, than it does not need get or set, what it needs is Fridge.go_shopping(). This way you have a method that is derived from the requirements, all "data" that it needs is local and you have actual behavior instead of just a thinly veiled data-structure.

Remember, you are not building a generic, reusable Fridge. You are building a Fridge for your requirements only. Any effort spent making it more than what it needs to be is actually wasteful.

Almost all of this shows a fundamental misunderstanding of encapsulation, and how it applies.

The initial response that you were breaking encapsulation is just wrong. Your application may have a need to simply set the value of cheese in the fridge instead of increment/decrement or add/remove. Also, it is not semantics, no matter what you call it, if you have a need to access and/or change attributes you don't break encapsulation by providing them. Finally, encapsulation is not really about "hiding", it's about controlling access to state and values that should not need to be public or manipulated outside of the class, while granting it to those that should and performing the task made available internally.

A getter or setter doesn't break encapsulation when there is a legitimate need to get or set a value. This is why methods can be made public.

Encapsulation is about keeping data and the methods that modify that data directly together in one logical place, the class.

In this particular case, there is clearly a need to change the value of cheese in the application. Regardless of how this is done, via get/set or add/remove, as long as the methods are encapsulated in the class you are following the object oriented style.

For clarification, I'll give an example of how encapsulation is broken by providing access regardless of method name or logical execution.

Say your fridge has a "lifetime", just a number of ticks before the fridge is no longer operational (for the sake of argument, the fridge can't be repaired). Logically there is no way a user (or the rest of your application) should be able to change this value. It should be private. It would only be visible through say a different public attribute known as "isWorking". When the lifetime expires, internally the fridge sets isWorking to false.

The execution of the lifetime counting down and its flipping the isWorking switch is all internal to the fridge, nothing outside could/should be able to effect the process. isWorking should only be visible, thus a getter does not break the encapsulation. However adding accessors for elements of the lifetime process would break your encapsulation.

Like most things, the definition of encapsulation is not literal, it's relative. Should you be able to see X outside of the class? Should you be able to change Y? Is everything that applies to your object here in this class or is the functionality spread across multiple classes?

It's not just renaming a method. The two methods function differently.

(Picture this in your mind)

get_cheese and set_cheese exposes the cheese. putCheese() and takeCheese() keeps the cheese hidden and takes care of managing it and give the user a way to handle it. The observer doesn't see the cheese, he/she only sees two methods of manipulating it.

ライセンス: CC-BY-SA帰属
所属していません softwareengineering.stackexchange
scroll top