An example illustrates the significance of the Richter substitution principle in Java design pattern programming

  • 2020-04-01 04:39:10
  • OfStack

The Richter substitution principle, OCP as a high-level OO principle, advocates the use of "Abstraction" and "Polymorphism" to replace static structure in design with dynamic structure, maintaining the closure of the design. "Abstraction" is a function provided by a language. "Polymorphism" is implemented by inheritance semantics.

The Richter substitution principle has the following four meanings:

A subclass can implement an abstract method of a parent class, but cannot override a non-abstract method of a parent class. Subclasses can add their own unique methods. When a subclass overrides or implements a method of a parent class, the preconditions of the method (that is, the parameters of the method) are looser than the input parameters of the parent method. When a method of a subclass implements an abstract method of a parent class, the postcondition of the method (that is, the return value of the method) is stricter than that of the parent class.

Now we can explain the four meanings above.

A subclass can implement an abstract method of a parent class, but cannot override a non-abstract method of a parent class

When we do system design, we often design interfaces or abstract classes, and then subclasses implement abstract methods, which is actually the Richter substitution principle. It is easy to understand that a subclass can implement the parent class's abstract methods, and in fact, a subclass must implement the parent class's abstract methods completely, even if it writes an empty method, otherwise it will compile and report an error.

The key to the Richter substitution principle is that you cannot override non-abstract methods of a parent class. Any method that is implemented well in a parent class is actually setting a set of specifications and contracts, and while it does not mandate that all subclasses comply with these specifications, if a subclass arbitrarily modifies these non-abstract methods, it will break the entire inheritance system. The Richter substitution principle expresses this.

In the object-oriented design, inheritance brings great convenience to the system design, but there are some potential risks. To illustrate the risks of inheritance, we need to perform A subtraction function, which is performed by class A.


class A{ 
  public int func1(int a, int b){ 
    return a-b; 
  } 
} 
 
public class Client{ 
  public static void main(String[] args){ 
    A a = new A(); 
    System.out.println("100-50="+a.func1(100, 50)); 
    System.out.println("100-80="+a.func1(100, 80)); 
  } 
} 

  Operation results:


100-50=50
100-80=20

              Later, we needed to add a new function: add two Numbers, and then sum with 100, with class B in charge. That is, class B needs to complete two functions:
Subtract two Numbers.
Add the two Numbers, and then add 100.
              Since class A has already realized the first function, after class B inherits class A, it only needs to complete the second function. The code is as follows:


class B extends A{ 
  public int func1(int a, int b){ 
    return a+b; 
  } 
   
  public int func2(int a, int b){ 
    return func1(a,b)+100; 
  } 
} 
 
public class Client{ 
  public static void main(String[] args){ 
    B b = new B(); 
    System.out.println("100-50="+b.func1(100, 50)); 
    System.out.println("100-80="+b.func1(100, 80)); 
    System.out.println("100+20+100="+b.func2(100, 20)); 
  } 
} 

After class B is completed, the result is:


100-50=150
100-80=180
100+20+100=220

              We found an error in the subtraction function that was working normally. The reason is that class B inadvertently overwrites the method of the parent class when naming the method, causing all the code running the subtraction function to call the method after class B overwrites, causing an error in the normal function. In this case, an exception occurs after subclass B replaces A reference to the functionality done by base class A. In actual programming, we often overwrite the methods of the parent class to complete new functions, which is simple to write, but the reusability of the entire inheritance system will be poor, especially when the application of polymorphism is frequent, the probability of program running errors is very large. If you have to override the methods of the parent class, it is more common to do so: the original parent class and the child class inherit from a more common base class, the original inheritance relationship is removed, and the use of dependency, aggregation, composition and other relations to replace.



Related articles: