Design pattern -- Richter substitution principle

Thinking and explanation of object-oriented relay inheritance

  1. Inheritance contains such a meaning: all implemented methods in the parent class are actually setting specifications and contracts. Although it does not force all subclasses to abide by these contracts, if subclasses modify these implemented methods arbitrarily, it will destroy the whole inheritance system.
  2. Inheritance not only 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.
  3. Inheritance is subject to the principle of Richter substitution.

Basic introduction

  1. If there is object o2 of type T2 for each object o1 of type T1, so that the behavior of program P does not change when all objects o1 are replaced with o2, then type T2 is a subtype of type T1. In other words, all references to the base class must be able to use the objects of its subclasses transparently.
  2. When using inheritance, follow the Richter substitution principle and try not to override the methods of the parent class in the subclass.
  3. The Richter substitution principle tells us that inheritance actually enhances the coupling between the two classes. In appropriate cases, the problem can be solved through aggregation, composition and dependency.

Case analysis

The following is an example of simple calculation

class A {
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

class B extends A{
    public int func1(int num1, int num2) {
        return num1 + num2;
    }
    public int func2(int num1, int num2) {
        return func1(num1, num2) + 9;
    }
}

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

     B b = new B();
    // The original intention is to calculate 11-3, but inadvertently rewriting the func1 method of class A will cause unnecessary errors
     System.out.println("11-3=" + b.func1(11, 3)); 
     System.out.println("1-8=" + b.func1(1, 8));
     System.out.println("11+3+9=" + b.func2(11, 3));
}

Problem analysis:

         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 complexity of the whole system will be poor, especially when running polymorphism is cumbersome.

resolvent:

        The original parent and child classes inherit a more popular base class. The original inheritance relationship is removed and replaced by dependency, aggregation, composition and other relationships. The implementation is as follows:

class Base {

}

class A extends Base{
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

class B extends Base {
    // If class B uses the method of class A, use the combination relationship
    private A a = new A();
    public int func1(int num1, int num2) {
        return num1 + num2;
    }
    public int func2(int num1, int num2) {
        return func1(num1, num2) + 9;
    }

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

public static void main(String[] args) {
    A a = new A();
    System.out.println("11-3=" + a.func1(11, 3));
    System.out.println("11-8=" + a.func1(11, 8));
    System.out.println("--------------------");
    B b = new B();
    // Because class B no longer inherits class A, the caller will no longer think that func1 is subtraction
    // The function completed by the call will be clear
    System.out.println("11+3=" + b.func1(11, 3)); 
    System.out.println("1+8=" + b.func1(1, 8));
    System.out.println("11+3+9=" + b.func2(11, 3));
}

Tags: Java Design Pattern

Posted on Fri, 26 Nov 2021 21:19:34 -0500 by volatileboy