Now I am reading the book PURE code on a small chapter about the law of Demeter. Prior to that, he encountered in patterns from O'reilly (HeadFirst) and there was a little bit clear. After a clean code - in the head of the mess. There are a couple of questions:

1) Martin divides objects into objects and data structures. What is meant by structure? Struct (in c # for example) or in general a class object in which there is nothing more than open fields (or properties) (methods, for example)?

2) The first question implies a misunderstanding of what is meant by a hybrid (half object, half data structure), which is better not to write. Is it considered a hybrid, for example, an object of the “Machine” class, where you can look at its color, even change the wheels, and have a behavior too?

3) This question was raised for oral discussion by other developers (we are not junas, but not “cool”) and there was also a misunderstanding of the very essence of this law, why it should be observed, which is the main reason: either the basis for further light-change, or hiding the internal structure of the object, or even the easy prevention and handling of a NullReferenceException? Everyone understands differently.

4) Is the law violated when dividing the "bad" methods into many small ones?

It was

public class Class1 { public String DoSmth() { //Вроде как закон нарушен, потому что вызываем метод у вернувшегося значения return MethodClass1().DoSmth(); } public Class2 MethodClass1() { return new Class2(); } } public class Class2 { public String DoSmth() { String res2 = this.MethodClass2(); return res2; } public String MethodClass2() { return "test"; } } 

It became

 public class Class1 { public String DoSmth() { //теперь тут вызываются только методы того же класса Class2 res1 = MethodClass1(); return this.MethodClass1_2(res1); } public Class2 MethodClass1() { return new Class2(); } public String MethodClass1_2(Class2 val) { return val.DoSmth(); } } 

Another small update: I personally have this attitude so far: this is some kind of rule, the need for explicit violation of which is an indicator that something is not so designed and you can find a solution that will be better both in business logic and in further escort.

  • 2
    "The Law of Demeter" sounds too categorical. I would call this statement "sometimes a useful rule of Demeter." - VladD

3 answers 3

In the book The Programmer-Pragmatist (Hunt, Thomas), Demeter's law (such a curved translation) is reduced to a short statement:

Minimize linking between modules

Example from a book in C ++

 class Demeter { private: A* a; int func(); public: void example(B& b); } void Demeter::example(B& b) { int f = func(); // 1 b.invert(); // 2 a = new A(); a->setActive(); // 3 C c; c.print(); // 4 } 

The law of Demeter for functions says that any method of a certain object can only refer to methods belonging to:

  1. to ourselves
  2. any parameters passed to the method
  3. any objects it creates
  4. any directly contained component objects

Based on this, you can answer your question number 3: reducing connectivity facilitates modification and maintenance of the code, facilitates writing tests.

In practice, this means that you have to create a large number of wrapper methods that simply send the request further to the delegate. These wrapper methods incur costs, degrading performance and taking up memory.

Turning the law of Demeter and tightly connecting several modules, you can get a performance benefit.

  • Well, so what if we have about the same code as I quoted in the 4th question. And we are changing it so that it satisfies the rule (judging by one of the comments (yours, by the way), my "satisfactory" option is really such). How can such shell methods in the same class reduce connectivity? - user2216
  • one
    @ user2216 - The MethodClass1_2 method MethodClass1_2 little connection with other code, which facilitates unit testing: you can pass a mock (stub) into it, instead of a real instance of Class2 . - Alexander Petrov

1) About the structure, he clearly writes there:

On the other hand, if ctxt, Options and ScratchDir are ordinary data structures that do not have behavior , they naturally reveal their internal structure, and the law of Demeter does not apply to them.

Behavior is in no way hidden if the calling code accesses the data directly, and not via get/set (this is a simple structure, as in C, for example). At the same time, if the call goes through get/set , it does not mean that some behavior is hidden there (it may be hidden there, but not a fact) and therefore:

The use of access functions makes the situation more difficult.

2) And about hybrids, it seems available:

Hybrids contain both functions for performing important operations, and open variables or open read / write methods that in all respects make private variables open.

In my opinion, hiding behavior is key. If there is any behavior and it is hidden, then this is an object, if there is no behavior, but simply open data, then this is a structure, and if there is both hidden behavior and open data, here’s a hybrid.

  • Thank! Look, my brain is tearing up such a problem. In an oop, an object is some kind of entity that has both a behavior and a state of some kind (field strength). And vyhoidt so that if (as I gave an example) there is a car, then it seems to be a hybrid, because the parameters are open to us (not all, but many), and it has behavior. And according to my observations, they are often such classes — they include both data and behavior. So, here comes Martin, who says that the hybrid is bad. And then what does he suggest? In my opinion, by definition, an object is a hybrid. - user2216
  • And in general, since programming calls for thinking to think about abstractions, and to rely on the concepts of business logic, then in fact - the objects of the real world are for the most part and have parameters, and behavior. Well, I guess I just complicate it, but I don’t understand what it is - user2216
  • one
  • one
    A hybrid is rather a structure, which for some reason was added a bit of behavior from business logic. Further on in the text about Active structures, he writes: “Unfortunately, developers often try to interpret data structures such as objects , and include business logic in them. However, this approach is undesirable because it creates a hybrid between the data structure and object. " - zed

I will answer the 4th question. If “By” and “Became” are left as they are, then the law is violated in both cases. What are the "violations" here:

  • Class1 is essentially a wrapper for Class2 (at least from the code you provided) - this behavior must be achieved by inheritance;
  • Class1 is very dependent on Class2 (Why is Class1, which is not a factory, creating an instance of Class2?).

Should "Become" like this:

 public class Class2 { public RETURN_TYPE DoSmth() { // Что-то там делается } } public class Class1 { public RETURN_TYPE DoSmth(Class2 val) { /* Тут должна быть какая-то логика, но не тупой возврат, вроде: return val.DoSmth(); */ } } 

It would be even better if an instance of the class Class2 is passed to the constructor of the class Class1 and addressed in the methods to an object of the class Class2 through the class1 property of the class - by the way, this is what the “Demeter's law” requires in this context. However, as a dependency, it is necessary to transfer not the class itself, but the interface that will implement Class2.

You yourself answered the third question in part - the code becomes easier to accompany, support, write tests, the code becomes less complicated for understanding, more opportunities when reusing the code (otherwise the code will be duplicated), the dependence of classes on each other decreases.

  • About the fourth question. It is clear that this is bydlokod, but this is just an example to show that from a code that exactly violates the law, you can make one that Martin’s definition ( albertroom.ru/posts/18 read from the second paragraph) does not seem to violate it, and does that mean he's normal? - user2216
  • one
    @ user2216 - Yes, exactly like this: it is normal. To strictly follow the law of Demeter, you have to write such shell methods. - Alexander Petrov
  • @user2216, you gave such an example of the separation of the "bad" method that you created not two "small", but simply two "bad" methods. Of course, with this approach, Martin is "not right." For the same link just below, a clarification is given of what is considered to be a violation of the law of Demeter, and what does not apply to it. - uorypm