According to Demeter’s law, is a class allowed to return one of its members?

I have three questions concerning Demeter’s law.

Apart from classes which were specifically appointed to return objects – such as factory and builder classes – is it okay for a method to return an object, e.g. an object held by one of the class’s properties or would that violate the law of demeter (1)? And if it violates the law of demeter, would it matter if the object returned is an immutable object that represents a piece of data and contains nothing but getters for this data (2a)? Or is such a ValueObject an anti-pattern in itself, because everything that is done with the data in that class is done outside of the class (2b)?

In pseudo code:

class A {}

class B {

    private A a;

    public A getA() {
        return this.a;
    }
}

class C {

    private B b;
    private X x;

    public void main() {
        // Is it okay for B.getA to exist?
        A a = this.b.getA();

        a.doSomething();

        x.doSomethingElse(a);
    }
}

I suspect that Demeter’s law forbids a pattern such as the above. What can I do to ensure that doSomethingElse() can be called while not violating the law (3)?

5

In many programming languages, all returned values are objects. As others have said, not being able to use the methods of returned objects forces you to never return anything at all. You should be asking your self, “What are the responsibilities of class A, B and C?” This is why using metasyntactic variable names like A, B and C always solicit the answer “it depends” because there is no inherit responsibilities in those terms.

You may want to look into Domain Driven Design, which will give you a more nuanced set of heuristics to reason about where functionality should go and who should be invoking what.

Your second question concerning immutable objects speaks to the notion of a
Value Object compared to an Entity object. in DDD, You can pass value objects around with almost no restrictions. This does not speak true for entity objects.

The simplistic LOD is much better expressed in DDD as the rules for accessing Aggregates. No external objects should hold references to members of aggregates. Only a root reference should be held.

DDD aside, you at least want to develop your own sets of stereotypes for your classes that are reasonable for your domain. Enforce rules about those stereotypes as you design your system.

Also always remember that all of these rules are to manage complexity, not to hamstring yourself.

4

According to Demeter’s law, is a class allowed to return one of its members?

Yes it most certainly is.

Let’s look at the main points:

  • Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
  • Each unit should only talk to its friends; don’t talk to strangers.
  • Only talk to your immediate friends.

All three of which leave you asking one question: Who is a friend?

When deciding what to return, The Law of Demeter or principle of least knowledge (LoD) does not dictate that you defend against coders that insist on violating it. It dictates that you do not force coders to violate it.

Getting these confused is exactly why so many think a setter must always return void. No. You must allow a way to make queries (getters) that do not change the state of the system. That’s basic command query separation.

Does this mean you’re free to delve into a code base chaining together whatever you want? No. Chain together only what was meant to be chained together. Otherwise the chain might change and suddenly your stuff is broken. This is what is meant by friends.

Long chains can be designed for. Fluent interfaces, iDSL, much of Java8, and good old StringBuilder are all meant to let you build long chains. They don’t violate LoD because everything in the chain is meant to work together and promised to keep working together. You violate demeter when you chain together stuff that never heard of each other. Friends are those that promised to keep your chain working. Friends of Friends did not.

Apart from classes which were specifically appointed to return objects – such as factory and builder classes – is it okay for a method to return an object, e.g. an object held by one of the class’s properties or would that violate the law of demeter (1)?

This only creates an opportunity to violate demeter. This is not a violation. This is not even necessarily bad.

And if it violates the law of demeter, would it matter if the object returned is an immutable object that represents a piece of data and contains nothing but getters for this data (2)?

Immutable is good but irrelevant here. Getting at stuff through a longer chain doesn’t make it better. What makes it better is separating the getting from the using. If you’re using, ask for what you need as a parameter. Don’t go hunting for it by delving into the getters of strangers.

In pseudo code:

I suspect that Demeter’s law forbids a pattern such as the above. What can I do to ensure that doSomethingElse() can be called while not violating the law (3)?

Before I talk about x.doSomethingElse(a) understand that you’ve basicly written

b.getA().doSomething()

Now, LoD is not a dot counting exercise. But when you create a chain you’re saying that you know how to get an A (by using B) and you know how to use an A. Well now A and B had better be close friends because you just coupled them together.

If you had just asked for something to hand you an A like thing you could use A and wouldn’t have cared where it came from and B could live a life happy and free of your obsession with getting A from B.

As for x.doSomethingElse(a) without details of where x came from, LoD has nothing at all to say about it.

LoD can encourage separating use from construction. But I will point out if you religiously treat every object as not friendly you’ll be stuck writing code in static methods. You can build a wonderfully complex object graph in main this way but eventually you have to call a method on it to start the thing working. You simply have to decide who your friends are. There’s no getting away from that.

So yes, a class is allowed to return one of its members under LoD. When you do you should make clear if that member is friendly with your class because if it’s not, some client may try coupling you to that class by using you to get it before using it. That’s important because now what you return must always support that use.

There are many cases where this is simply not a concern. Collections can ignore this simply because they are meant to be friends with everything that uses them. Similarly value objects are friendly with everyone. But if you wrote an address validating utility that demanded an employee object that it extracted an address from, rather then just ask for the address, well you’d better hope that the employee and address both came from the same library.

2

Apart from classes which were specifically appointed to return objects […]

I don’t quite understand this argument. Any object can return an object as a result of a message invokation. Especially if you think in “everything as object”.

Classes however, are the only objects that can instantiate new objects of their own kind by sending them the “new” message (or often replaced with a new keyword on most common OOP languages)


Anyway, regarding your question I’d be rather suspicious about an object returning one of its properties in order to be used elsewhere. It could be that this object would be leaking out information about either its state or its implementation details.

And you wouldn’t want the C object to know about implementation details of B. This is an unwanted dependency on the A object from the C object perspective.

So you may want to ask yourself if C, by knowing A, is not knowing too much for the work he has to do, independently of the LOD.

There are cases where this can be legitimate, for example, asking a collection object for one of its items is appropriate and not breaking any Demeter rule. Asking a Book object for its SQLConnection object on the other hand, is risky and should be avoided.

The LOD exists because many programmers tend to ask objects for information before performing a work out of it. LOD is there to remind us that sometimes (if not always) we’re just over-complicating things by wanting our objects to do too much. Sometimes we just have to ask another object to do the work for us. LOD is there to makes us think twice about where we place the behaviour in our objects.

Apart from classes which were specifically appointed to return objects – such as factory and builder classes – is it okay for a method to return an object?

Why wouldn’t it be? You seem to suggest that it’s necessary to signal to your fellow programmers that the class is specifically meant to return objects, or it must not return objects at all. In languages where everything is an object, this would severely limit your options, as you wouldn’t be able to return anything at all.

7

Depends on what you are doing. If you expose a member of your class, when it’s nobody’s business that this is a member of your class, or what the type of that member is, that’s a bad thing. If you then change the type of that member, and the type of the function returning the member, and everyone has to change their code, that is evil.

On the other hand, if the interface of your class states that it will supply an instance of a well-known class A, that’s fine. If you are lucky and you can do this by supplying a member of your class, good on you. If you changed that member from being an A to being a B, you would then need to rewrite the method that returns an A, obviously it will now have to construct one and fill it with available data, instead of just a one-liner returning a member. The interface of your class would be unchanged.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *