“This article has participated in the call for good writing activities, click to view: the back end, the big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!”

I. What is Demeter’s rule

The Law of Demeter is also called the least knowledge principle, which states that one object should know as little as possible about other objects. Don’t talk to strangers. Short for LoD.

The purpose of Demeter’s rule is to reduce coupling between classes. Because each class minimizes its dependence on the others, it is easy to make the functional modules of the system functionally independent, with no (or few) dependencies on each other.

Demeter’s rule does not want direct connections between classes. If you really need to make a connection, you want to communicate it through its friend class. Therefore, one possible consequence of applying Demeter’s rule is the existence of a large number of mediation classes, which exist solely for the purpose of passing on the intercalling relationships between classes — which increases the complexity of the system to some extent.

Two. Why Demeter’s Law?

There are well-known abstractions in object-oriented programming, such as encapsulation, cohesion, and coupling, that can theoretically be used to produce clean designs and good code. While these are very important concepts, they are not practical enough to be applied directly to a development environment; they are subjective and rely heavily on the experience and knowledge of the user. The same is true for other concepts, such as the principle of single liability, the open-closed principle, etc. What makes Demeter’s law unique is its concise and precise definition, which allows it to be applied directly when writing code, almost automatically applying appropriate encapsulation, low cohesion, and loose coupling.

Iii. The broad and narrow sense of Demeter’s law

3.1. Demeter’s Rule in a narrow sense

If two classes do not have to communicate directly with each other, then the two classes should not interact directly. If one of these classes needs to call a method of another class, the call can be forwarded by a third party.

The “friend” condition of the circle of friends is: 1) the current object itself (this) 2) the object passed as a parameter to the current object method. 3) The instance variable of the current object directly refers to the object specified in a class. The properties in the instance variable of the current object refer to other objects, so the instance of the object is friends with the current instance. 4) The instance variable of the current object is friends with the current instance. If the attribute is an object, then both the attribute and the element in the object are friends. 5) The object created by the current object

Any object that meets one of the above conditions is a “friend” of the current object; Otherwise, it’s a stranger.

Disadvantages of the narrow Demeter’s rule:

Make a lot of small methods in the system that just pass indirect calls and have nothing to do with the business logic of the system. Following Demeter’s rule between classes would be a local design simplification of a system, since each part would not have a direct connection to distant objects. However, this will also reduce the communication efficiency between different modules of the system, and make it difficult to coordinate between different modules of the system.

2. The embodiment of generalized Demeter’s Law in class design:

Making a class immutable is a priority. Minimize access to a class. Use Serializable with caution. Minimize the access rights of members.Copy the code

Application of Demeter’s law in design mode

Design pattern Facade and Mediator are both applications of Demeter’s law

So let’s take the example of renting a house, and look at Demeter’s rule. Usually customers want to find a house to live in, we directly build a house class, build a customer class, customers can find a house.

public interface IHouse {
    / / house
    public void Housing(a);
}

public class House implements IHouse{

    @Override
    public void Housing(a) {
        System.out.println("Live in a house"); }}public class Customer {
    public String name;

    public void findHourse(IHouse house) { house.Housing(); }}Copy the code

The client is looking for a house to live in, the logic is very simple, this is OK. It violates Demeter’s law, but it makes sense. But usually when we look for a house, we don’t find it all at once. We have to find a lot of houses, so it’s a lot of trouble. The agent has a lot of house resources, and the landlord gives the house to the agent, without caring who the tenant is. The tenant leaves the job of finding a house to the landlord, and he doesn’t have to care who the landlord is. Moreover, both the tenant and the landlord are very convenient.

/** * house */
public interface IHouse {
    / / house
    public void Housing(a);
}

public class House implements IHouse{

    @Override
    public void Housing(a) {
        System.out.println("Live in a house"); }}public interface ICustomer {

    void findHourse(IHouse house) ;
}

public class Customer implements ICustomer {

    public void findHourse(IHouse house) { house.Housing(); }}/** ** intermediate */
public class Intermediary {
    / / looking for a house
    public IHouse findHouse(ICustomer customer){
        // Help tenants find apartments
        return null; }}Copy the code

The house, the client is independent of each other, no reference to each other. The relationship between them was established through an intermediary. In other words, the client finds an intermediary to rent a house, the landlord gives the house to the tenant, and the intermediary finally gives the good house to the client. Clients and landlords are segregated from each other, in accordance with Demeter’s law.

Practice of Demeter’s Rule

So how in practice should one object know the least about the other? If we think of an object as a person, then two things are enough to achieve “a person should know the least about another person” : 1. Talk only to direct friends; 2. Know less about your friends. Here’s how to do both.

1. Only talk to direct friends

Another English interpretation of Demeter’s rule is: Talk only to your immediate friends.

What is a friend?

Every object is bound to be coupled to other objects, and the coupling between the two objects becomes a friend. So what is a direct friend? Classes that appear in input and output parameters of member variables and methods are immediate friends. Demeter’s Law requires that you correspond only with direct friends.

Note: Classes that appear only inside the method body are not direct friends, and if a class communicates with a friend that is not direct, it violates Demeter’s law.

Let’s take an example of what a friend is and what a direct friend is. A simple example: The teacher asked the monitor to count the number of the class. There are three classes in this example: Teacher, monitor GroupLeader, and Student.


public interface ITeacher {
    void command(IGroupLeader groupLeader);
}

public class Teacher implements ITeacher{
    @Override
    public void command(IGroupLeader groupLeader) {
        // The whole class
        List<Student> allStudent = new ArrayList<>();
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        // The monitor counted the number of peoplegroupLeader.count(allStudent); }} ** * Class monitor */public interface IGroupLeader {

    // The monitor counted the number of people
    void count(List<Student> students);
}

/**
 * 班长类
 */
public class GroupLeader implements IGroupLeader{
    /** * The monitor counts the number *@param students
     */
    @Override
    public void count(List<Student> students) {
        // The monitor counted the number of people
        System.out.println("The number of students in class is:"+ students.size()); }}/** ** class */
public interface IStudent {}/** ** class */
public class Student implements IStudent {}/** * client */
public class Client {
    public static void main(String[] args) {
        / / the teacher class
        ITeacher wangTeacher = new Teacher();

        / / monitor
        IGroupLeader zhangBanzhang = newGroupLeader(); wangTeacher.command(zhangBanzhang); }}Copy the code

Running results:

The number of students in class is: 5

In this example, how many friends does our Teacher have? GroupLeader is an input parameter to Teacher’s command() method. The other is Student, because Student is used in the body of the Teacher’s command() method.

How many direct friends does Teacher have? By the definition of an immediate friend

Classes that appear in input and output parameters of member variables and methods are immediate friends

Only group Reader is Teacher’s direct friend.

Teacher creates an array of students in the command() method and communicates with the indirect friend Student, so the above example violates Demeter’s rule. A method is a behavior of a class, and a class is not allowed to know that its behavior is dependent on another class, which is a serious violation of Demeter’s law!

To make the above example comply with Demeter’s rule, we can modify it as follows:

public interface ITeacher {
    void command(IGroupLeader groupLeader);
}

public class Teacher implements ITeacher {
    @Override
    public void command(IGroupLeader groupLeader) {
        // The monitor counted the number of peoplegroupLeader.count(); }}/**
 * 班长类
 */
public interface IGroupLeader {
    // The monitor counted the number of people
    void count(a);
}

/**
 * 班长类
 */
public class GroupLeader implements IGroupLeader {

    private List<Student> students;

    public GroupLeader(List<Student> students) {
        this.students = students;
    }

    /** * The monitor counts the number */
    @Override
    public void count(a) {
        // The monitor counted the number of people
        System.out.println("The number of students in class is:"+ students.size()); }}/** ** class */
public interface IStudent {}/** ** class */
public class Student implements IStudent {}/** * client */
public class Client {
    public static void main(String[] args) {
        / / the teacher class
        ITeacher wangTeacher = new Teacher();

        List<Student> allStudent = new ArrayList(10);
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());
        allStudent.add(new Student());

        / / monitor
        IGroupLeader zhangBanzhang = newGroupLeader(allStudent); wangTeacher.command(zhangBanzhang); }}Copy the code

Running results:

The number of students in class is: 4

This modification allows each class to communicate only with its immediate friends, effectively reducing the coupling between classes

2. Know less about your friends

How to know less about your friends? If your friend is a big talker, he will talk in front of you and tell you all his stories even if you don’t ask him. So, to reduce the knowledge of a friend, please switch to a more introverted friend ~ in a class, is to minimize a class exposed methods.

Take a simple example of a class that exposes too many methods. The process of a person using a coffee machine to make coffee, there are only two classes in the example, one is a person, the other is a coffee machine.

The first is CoffeeMachine, which only needs three methods to make coffee: 1. Add coffee beans; 2. Add water; 3. Make coffee:

/** ** coffee machine abstract interface */
public interface ICoffeeMachine {

    // Add coffee beans
    void addCoffeeBean(a);

    / / add water
    void addWater(a);

    // Make coffee
    void makeCoffee(a);
}


/** ** coffee machine implementation class */
public class CoffeeMachine implements ICoffeeMachine{

    // Add coffee beans
    public void addCoffeeBean(a) {
        System.out.println("Put the coffee beans.");
    }

    / / add water
    public void addWater(a) {
        System.out.println("Water");
    }

    // Make coffee
    public void makeCoffee(a) {
        System.out.println("Make coffee."); }}/** * people, make coffee */
public interface IMan {
    /** ** make coffee */
    void makeCoffee(a);
}

/** * people make coffee */
public class Man implements IMan {
    private ICoffeeMachine coffeeMachine;

    public Man(ICoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    /** ** make coffee */
    public void makeCoffee(a) { coffeeMachine.addWater(); coffeeMachine.addCoffeeBean(); coffeeMachine.makeCoffee(); }}/** * client */
public class Client {
    public static void main(String[] args) {
        ICoffeeMachine coffeeMachine = new CoffeeMachine();

        IMan man = newMan(coffeeMachine); man.makeCoffee(); }}Copy the code

Running results:

Add water and coffee beans to make coffee

In this example, CoffeeMachine is Man’s direct friend, but the problem is that Man knows too much about CoffeeMachine, and actually he doesn’t care about the specific process of coffee making. So we can optimize as follows:

Make addCoffeeBean, addWater, and makeCoffee private: addCoffeeBean, addWater, makeCoffee


/** ** coffee machine abstract interface */
public interface ICoffeeMachine {

    // The coffee machine works
    void work(a);

}

/** ** coffee machine implementation class */
public class CoffeeMachine implements ICoffeeMachine {

    // Add coffee beans
    public void addCoffeeBean(a) {
        System.out.println("Put the coffee beans.");
    }

    / / add water
    public void addWater(a) {
        System.out.println("Water");
    }

    // Make coffee
    public void makeCoffee(a) {
        System.out.println("Make coffee.");
    }

    @Override
    public void work(a) { addCoffeeBean(); addWater(); makeCoffee(); }}/** * people, make coffee */
public interface IMan {
    /** ** make coffee */
    void makeCoffee(a);
}


/** * people make coffee */
public class Man implements IMan {
    private ICoffeeMachine coffeeMachine;

    public Man(ICoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    /** ** make coffee */
    public void makeCoffee(a) { coffeeMachine.work(); }}/** * client */
public class Client {
    public static void main(String[] args) {
        ICoffeeMachine coffeeMachine = new CoffeeMachine();

        IMan man = newMan(coffeeMachine); man.makeCoffee(); }}Copy the code

After such modification, Man’s understanding of CoffeeMachine is reduced by reducing CoffeeMachine’s external exposure, thus reducing the coupling between them.

In practice, Demeter’s law can be satisfied by communicating only with immediate friends and knowing less about them. So it’s not hard to imagine that the purpose of Demeter’s rule is to turn our classes into fat nerds. “Fat” is that a class may have few exposed methods, but its internal implementation may be very complex (this explanation is a stretch ~). Indoorsy because it only communicates with immediate friends. Fat otaku is a derogatory term in real life, but it has become a social problem in Japan. But in the program, a “fat nerd” class is an example of a good class.

Six. Precautions

First: in the division of classes, we should create weak coupling classes, the weaker the coupling between classes, the more conducive to achieve the goal of reusable. Second: In class structure design, each class should reduce the access rights of members. Third: in class design, whenever possible, a class should be designed to be unchanging. Fourth: In the reference to other classes, one object to the object of another class should be minimized. Fifth: try to limit the effective range of local variables, reduce the access rights of classes.Copy the code