Design Patterns: Liskov Substitution Principle (Detailed Explanation)



foreword

This blogger will use CSDN to record the experience and knowledge he has personally gained and learned on the way to study software development. Interested friends can pay attention to the blogger! Perhaps a person can go fast alone, but a group of people can go farther!

1. Introduction

(1) Import

  1. Inheritance contains such a layer of meaning: all methods that have been implemented in the parent class are actually setting specifications and contracts . Although it does not mandate that all subclasses must follow these contracts, if the subclass has implemented these Any modification of the method will cause damage to the entire inheritance system.

  2. While inheritance brings convenience to program design, it also brings disadvantages.
    For example:
    ● The use of inheritance will bring intrusion to the program;
    ● Reduce the portability of the program;
    ● Increase the coupling between objects;
    ● If a class is inherited by other classes, when this class needs to be modified, it must be considered To all subclasses, and after the parent class is modified, all functions related to the subclasses may cause failures

  3. The question is raised: In programming, how to use inheritance correctly? => Liskov Substitution Principle

(2) Basic introduction

  1. The Liskov Substitution Principle ( LSP ) was proposed in 1988 by Ms. Li from the Massachusetts Institute of Technology.

  2. If for every object o1 of type T1, there is an object o2 of type T2 such that all programs P defined by T1 do not change their behavior when all objects o1 are replaced by o2, then the type T2 is a subtype of type T1. In other words, all places that refer to the base class must be able to use objects of its subclass transparently.

  3. When using inheritance, follow the Liskov substitution principle, and try not to override the methods of the parent class in the subclass .

  4. The Liskov substitution principle tells us that inheritance actually enhances the coupling of two classes, and under appropriate circumstances, problems can be solved through aggregation, composition, and dependency.

2. Code demo

1. Version 1: Original version

public class Liskov {
     
     

	public static void main(String[] args) {
     
     
		// TODO Auto-generated method stub
		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));//这里本意是求出11-3
		System.out.println("1-8=" + b.func1(1, 8));// 1-8
		System.out.println("11+3+9=" + b.func2(11, 3));
		
		

	}

}

// A类
class A {
     
     
	// 返回两个数的差
	public int func1(int num1, int num2) {
     
     
		return num1 - num2;
	}
}

// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends A {
     
     
	//这里,重写了A类的方法, 可能是无意识
	public int func1(int a, int b) {
     
     
		return a + b;
	}

	public int func2(int a, int b) {
     
     
		return func1(a, b) + 9;
	}
}
  1. We found that the subtraction function that was working normally had an error. The reason is that class B inadvertently rewrites the method of the parent class, causing errors in the original function. In actual programming, we often complete new functions by rewriting the method of the parent class. Although it is simple to write, the reusability of the entire inheritance system will be relatively poor. Especially when running polymorphism more frequently.
  2. The general approach is: both the original parent class and subclass inherit a more popular base class, the original inheritance relationship is removed, and dependencies, aggregation, combination and other relationships are used instead.

2. Version 2: Liskov Substitution Principle

public class Liskov {
     
     

	public static void main(String[] args) {
     
     
		// TODO Auto-generated method stub
		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();
		//因为B类不再继承A类,因此调用者,不会再func1是求减法
		//调用完成的功能就会很明确
		System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3
		System.out.println("1+8=" + b.func1(1, 8));// 1+8
		System.out.println("11+3+9=" + b.func2(11, 3));
		
		
		//使用组合仍然可以使用到A类相关方法
		System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3
		

	}

}

//创建一个更加基础的基类
class Base {
     
     
	//把更加基础的方法和成员写到Base类
}

// A类
class A extends Base {
     
     
	// 返回两个数的差
	public int func1(int num1, int num2) {
     
     
		return num1 - num2;
	}
}

// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends Base {
     
     
	//如果B需要使用A类的方法,使用组合关系
	private A a = new A();
	
	//这里,重写了A类的方法, 可能是无意识
	public int func1(int a, int b) {
     
     
		return a + b;
	}

	public int func2(int a, int b) {
     
     
		return func1(a, b) + 9;
	}
	
	//我们仍然想使用A的方法
	public int func3(int a, int b) {
     
     
		return this.a.func1(a, b);
	}
}

Guess you like

Origin blog.csdn.net/weixin_52533007/article/details/130406911