2

This is a simple scenario for understanding this problem about persons and their house.

Person can change color of their House

I created this UML diagram:

enter image description here

As shown in above diagram:

  • A Person can change their house color. To show that, I use changeHouseColor() method in the class Person.
  • In the House class changeColor() method is for changing its color attribute.

I would implement the above scenario using java code as shown below. Please note this code as pseudo code, so syntax can be wrong.

class Person {
    private House house;

    Person(House house) {
        this.house = house;
    }

    public void changeHouseColor() {
        house.changeColor(); // Delegation call
    }
}
class House {
    private String color;

    public string getColor() {
        return color;
    }

    public void changeColor(String color) {
        this.color = color;
    }
}

I want to know:

  • To show that a person can change his house color, I used the Person.changeHouseColor() method. Does adding this method violate encapsulation?
  • If this method is not needed in Person class, then how to show that a person can change his house color?
  • In OOAD is it not mandatory that the person's actions are included as methods in person class?
Christophe
  • 68,716
  • 7
  • 72
  • 138
Susantha7
  • 898
  • 1
  • 20
  • 38
  • Rather than `person.getHouse().changeColor(color)`? – Mr. Polywhirl Jan 02 '20 at 13:58
  • 1
    If you cannot access the `House` directly from the `Person` then this is acceptable. – Mr. Polywhirl Jan 02 '20 at 14:02
  • `person.getHouse().changeColor(color)` but this is not showing that the person class is doing the color change – Susantha7 Jan 02 '20 at 16:35
  • 1
    is it not mandatory that person's actions include as methods in `person` class – Susantha7 Jan 02 '20 at 16:37
  • Your association is wrong. That's an Extends relation. Use an open arrow or none / role names and dot notation. – qwerty_so Jan 02 '20 at 23:27
  • A funny house you have that has a changeColor() operation. How that? Different illumination? Wouldn't work at daylight, I guess. – qwerty_so Jan 02 '20 at 23:28
  • Why would you need that operation at all? If it's only changing the property you can as well make it a public attribute. It's anyway public. Any sprayer can come by and prove that true (although it's not legal). – qwerty_so Jan 02 '20 at 23:33
  • 1
    IMHO it doesn't violate encapsulation, but it can violates sometimes the single responsibility principle. There's no exact answer on your question because they highly dependent from a context where the classes are used. It like to ask how reasonable to use these two words together without knowledge of whole sentence and a topic of the text – edwgiz Jan 09 '20 at 11:20

3 Answers3

2

In general there is nothing wrong in both person.changeHouseColor(color) and person.getHouse().changeColor(color). What approach is better depends on your domain.

We can say person.getHouse().changeColor(color) violates the Law of Demeter (LOD) or principle of least knowledge. The idea is to have knowledge only about "closely" related classes. Classes having an instance of Person should not depend on its internal structure and instead call only methods of the Person: person.changeHouseColor(color).

This approach has both advantages and disadvantages. The main advantage is the ability to change the internal structure of classes (Person class) without reworking their clients.

It definitely does not violates the encapsulation paradigm. Restricting the direct access to some of object's components can be even treated as better encapsulation.

A disadvantage is the need to write many wrapper methods to propagate calls to delegates.

But if you want to express that only person can change change a House color than the model is not ideal probably. Because any class that has an access to a House instance can call house.changeColor(color) directly without even having a Person instance. And there will be a House instance at least in the method that creates it:

House house = new House(Color.WHITE);
Person person = new Person(house);
person.changeHouseColor(Color.ORANGE); //OK
house.changeColor(Color.WHITE); //should we allow it?

This aspect depends a lot on the domain. It's important to identify Aggregates in your domain.

Eugene Khyst
  • 9,236
  • 7
  • 38
  • 65
1

In short

Fundamentally, there is no universal right or wrong to this question. It all depends on the responsibilities that you want to give to your classes in their collaborations. But in the majority of the cases, don't !

Pros - When to do this ?

If it's the sole responsibility if the Person to change the color, and nobody else should care about the House, then your design makes sense. It has the the advantages of hiding the delegation as already nicely explained by SDJ.

But this is not the sole way to distribute the responsibilities between the classes, and there are many reasons to leave the design more open, for example: What if the Person doesn't paint her house herself, but asks a Painer to do the job on her behalf? What if, hypothetically, the mayor of the village would have the power to decide on the change of color, and send his painters accross the village ?

Cons - avoid it if possible !

There is a big disadvantage in your design. It has to do with the Single Responsibility Principle (SRP):

A class should have only one reason to change

Adding changeHouseColor implies that Person has more than one reason to change: first it may change with the concept of Person itself. But it might then also have to change as consequences of changes in House. For example, if tomorrow, the interface of House evolves to require an additional thickness parameter for changeColor, not only would your Person implementation change (providing the additional parameter in the delegation call), but also the Person interface would have to change, so that the thickness is provided as well. So a small change in House would propagate to all the class using Person. The hidden coupling can quickly become a technical debt.

If you start to replicate every method in every class that could remotely access it, you will further face a combinatorial explison in your interfaces, which would quickly freeze the evolution of any interface because of the risk of change propagation.

Conclusion

Separation of concerns should drive your design. If the concept of Person is independent of the concept of House, do not couple them unnecessarily. Do this only if there is a strong need to do so (for example if the house is private and nobody has to know anything about it).

Also, in UML there is no need to add changeHouseColor() method to show that a person can change the colour of the house. The simple association between Person and House shows that Person can invoke any public method of House.

If you provide a getHouse() in Person, or if you'd add a public +myHouse at the house end of the association, you would also communicate that other classes can access a Person's House

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • [ The simple association between Person and House shows that Person can invoke any public method of House] then person can invoke methods in the `House` class which can consider as behaviors of other classes(other classes associated with `House class`) – Susantha7 Jan 08 '20 at 15:31
  • Preson can change house color using `Preson .changeHouseColor()` method it's associated method in `House` class is `changeColor()` . Termite can decrease house Strength using `Termite.decreaseHouseStrength()` method it's associated method in `House` class is `changeStength()` – Susantha7 Jan 08 '20 at 15:44
  • according to you then `Person` class can access `changeStength()` method but person has nothing to do with `House` strength. then how to prevent person class access `House.changeStength()` – Susantha7 Jan 08 '20 at 15:45
  • @Susantha7 yes. The design should ensure that the behaviors of house are relevant, whoever invokes this method. The class should shape the collaboration and not the contrary. This is a consequence of the principle of separation of concerns, and a core principle if you want to achieve maintainable software with low coupling. More here: http://c2.com/doc/oopsla89/paper.html – Christophe Jan 08 '20 at 15:47
  • @Susantha7 and this is a reason more for not adding changeHouseColor to a person: in reality the responsibility to set the color belongs to the house and other entities could also invoke it. Also be careful with the analogies. In the real world the color of the house is defined not by the house but by the paint, and the paint can be put on the house by anyone having the will to paint, disposing of paint, and having access to the house regardless of legal rights on the object. – Christophe Jan 08 '20 at 15:53
1

In short my answers are:

  1. No, encapsulation is not violated.
  2. The fact that the Person can change the color is already given by the Association.
  3. The Person's actions can involve calling its own Operations, but many other actions are possible.

Further Explanations:

point 1: Encapsulation in its formal description just says, you should not directly use the attributes of other Classes. It is completly Ok to call an Operation of another Class and it is Ok to offer an own Operation that delegates something to another Class. Whether it is good design depends on your specifc domain, as the other answers have suggested.

point 2: When a Class has access to instances of another Class, it can potentially use all of its public Features. In your example, there is an Assocation between Person and House. Therefore, Person can call changeColor, but is not required to do it. In a more complete model House could have many more Features and not all of them might be meant to be used by Person. In this case it is useful to define a client specific Interface, only containing the Features needed by the Person Class. The Association would then be directed to this Interface, which in turn gets realized by the House Class. The Person Class is still technically not required to use all the Features of the Interface. However, I would view an Association to an Interface as a strong indication of the modelers intent, that all Features get used eventually.

point 3: In OOAD Activity Diagrams are commonly used for analysing Use Cases. In this case the Actions are not connected to specific Classes and therefore no Operations are defined in this step.

In a complete design model, the Behavior of the Person Class would be specified somehow. It could be with an Activity. In this Activity there could be many Actions. One could be a CallOperationAction, that calls changeColor. This would be an explicit specification of how the Person Class uses the House Class. It could also call its own Operation changeHouseColor, which in turn could be specified with an Activity.

There are many other Actions defined in UML, like ReadStructuralFeatureAction or CreateObjectAction. They are not used very often, since it doesn't make much sense to model at this level of detail. However, I think it is helpful to know about them, to better understand how Operations and Actions are connected.

Axel Scheithauer
  • 2,758
  • 5
  • 13
  • in point 2 [[In this case it is useful to define a client specific Interface]] can you explain this is this interface for `Person` class – Susantha7 Jan 08 '20 at 16:46
  • "In this case it is useful to define a client specific Interface, only containing the Features needed by the Person Class." this means interface for `House` class am i right – Susantha7 Jan 09 '20 at 05:03
  • 1
    @Susantha7: Yes, an Interface realized by the `House` Class and used, via an Association, by the `Person` Class. It would only have one Operation `changeColor()` and thus could be named `Colorable`. – Axel Scheithauer Jan 13 '20 at 18:00