Seven principles of design pattern -- Richter's replacement principle

1. What is the Richter substitution principle?

As we all know, there are three characteristics (encapsulation, inheritance and polymorphism) in object-oriented programming. Here, let's inherit this thing.

Inheritance contains such a layer of meaning: all implemented methods in the parent class are actually setting specifications and contracts. Although it does not force all subclasses to follow these contracts, if subclasses arbitrarily modify these implemented methods, it will damage the whole inheritance system.

In other words: inheritance brings convenience to program design, but also brings disadvantages. For example, using inheritance will bring invasiveness to the program, reduce the portability of the program and increase the coupling between objects. If a class is inherited by other classes, all subclasses must be considered when the class needs to be modified, and all functions involving subclasses may fail after the parent class is modified.

The question is: how to use inheritance correctly in programming? = > Richter substitution principle 👇👇👇

  1. The Liskov Substitution Principle was proposed by a woman surnamed Li of MIT in 1988.
  2. If for each object o1 of type Tl, there is an object o2 of type T2, so that all programs defined in Tl Р When all objects o1 are replaced with o2, the program Р If there is no change in the behavior of, then type T2 is a subtype of type TI. In other words, all references to the base class must be able to use the objects of its subclasses transparently.
  3. When using inheritance, follow the Richter substitution principle and try not to override the methods of the parent class in the subclass.
  4. The Richter substitution principle tells us that inheritance actually enhances the coupling between the two classes. Under appropriate circumstances, the problem can be solved through aggregation, composition and dependency.

2. Code case

package com.szh.principle.liskov;

/**
 *
 */
// Class A
class A {
    // Returns the difference between two numbers
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

// Class B inherits class A
// Added a new function: complete the addition of two numbers, and then sum with 9
class B extends A {
    //Here, the method of class A is rewritten, which may be unconscious
    public int func1(int a, int b) {
        return a + b;
    }

    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }
}

public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" + a.func1(11, 3));
        System.out.println("1-8=" + a.func1(1, 8));
        System.out.println("-----------------------");

        B b = new B();
        System.out.println("11-3=" + b.func1(11, 3));  //The original intention here is to find 11-3
        System.out.println("1-8=" + b.func1(1, 8));    //The original intention here is to find 1-8
        System.out.println("11+3+9=" + b.func2(11, 3));
    }
}

From the code running results, we can see that there are two lines with problems. This is because after B inherits a and rewrites the func1 method, it will not execute the func1 method of class A, but B's own func1 method. The logic of func1 method in B is to sum two numbers, so what you think here is no longer what you think.

3. Improvement code

We found an error in the subtraction function that was working normally. The reason is that class B inadvertently rewrites the method of the parent class, resulting in errors in the original function. In actual programming, we often complete new functions by rewriting the parent class. Although it is simple to write, the reusability of the whole inheritance system will be poor. Especially when running polymorphism more frequently.

The common approach is: the original parent and child classes inherit a more popular base class, remove the original inheritance relationship, and replace it with dependency, aggregation, combination and other relationships.

package com.szh.principle.liskov.improve;

/**
 *
 */
//Create a more basic base class
class Base {
    //Write more basic methods and members to the Base class
}

// Class A
class A extends Base {
    // Returns the difference between two numbers
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

// Class B inherits class A
// Added a new function: complete the addition of two numbers, and then sum with 9
class B extends Base {
    //If B needs to use the method of class A, use the combination relationship
    private A a = new A();

    //Here, the method of class A is rewritten, which may be unconscious
    public int func1(int a, int b) {
        return a + b;
    }

    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }

    //We still want to use the method of A
    public int func3(int a, int b) {
        return this.a.func1(a, b);
    }
}

public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" + a.func1(11, 3));
        System.out.println("1-8=" + a.func1(1, 8));
        System.out.println("-----------------------");

        B b = new B();
        //Because class B no longer inherits class A, the caller will no longer think that func1 method is subtraction
        //The function completed by the call will be clear
        System.out.println("11+3=" + b.func1(11, 3));//The original intention here is to find 11 + 3
        System.out.println("1+8=" + b.func1(1, 8));//The original intention here is to find 1 + 8
        System.out.println("11+3+9=" + b.func2(11, 3));
        //Class A related methods can still be used in combination
        System.out.println("11-3=" + b.func3(11, 3));// The original intention here is to find 11-3
    }

}

At this time, we create A more basic Base class, and let both A and B inherit this class. If we still want to use A in B as before, we can use combination to solve it, that is, declare A private class A member variable in class B.

Keywords: Java Design Pattern

Added by mudkicker on Sun, 06 Feb 2022 04:58:57 +0200