00:00
好的,那现在呢?我们来看一个理事替换原则的实际案例,我们先来看这么一段代码。这段代码呢,其实比较简单,它是这样子的,有一个A类。这个A类里面有个方法叫FUNCTION1,它返回两个数的差,看到没有,这个地方有一个B类,B类呢继承了A类,它在这里面呢,重写了方克金一,也就是说他有可能是不小心对吧,或者说他本意并不是想去重写,但是呢,他无意。去把这个A类进行了一个重写,但是他并没有发现,紧接着呢,他又写了一个function function2。FUNCTION2里面呢,调用了FUNCTION1,这个FUNCTION1它是想干一件什么事情呢?它是要调FUNCTION1里面的这个方法,把两个数的和返回来再加一,于是它后面进行了一个调用,大致是这样子的,我们先把代码。写一下,好,我们先把这个代码写一下,看看它的问题在什么地方。
01:03
我们新建一个包。新建一个包,OK,那这个包呢,我们取个名字。理事替换原则,我们就用这个名字好吧。用它。然后呢,新建一个包。小写一下。好的,然后呢,我们写一个小案例。对。呃。就这,就这,就写这么一个名字吧。然后写一个主方法。写个主方法,里边呢,这些比较简单的代码,我们拿过来用就可以了,这有个A类没问题吧,大家大家一看就应该明白,这有一个A类格式化。我这儿做一些简单的注释。对A类,这个A类里面有一个方法叫function,一,它返回两个数的差。
02:01
对不对?OK,他紧接着又写了一个类,叫B类。B类我们注意一下这个B类,我们可以看到B类呢,它继承了A类,看到这里呢,他写了一个FUNCTION1,他是想干一件什么事情呢?他的本意是想做这件事情,就是他增加了一个。新的功能。它增加一个新的功能干什么呢?完成两个。两个数相加。然后,然后。然后和谁呢?和九求和。并这个事情由B来完成。但是他在写这个代码的时候,他无意间把这个function重写了。对,他无意间把这个方式出现,但是他有可能没有意识到,对吧,他没有意识到,那这个时候他在调用这个代码的时候呢,他是这样来调的,来我们把这段代码拿过来用一下。
03:08
代码都很简单哈,各位朋友。那这段代码他做了一个,做了一个怎么样的操作呢。我格式化一下,它是这样子的。它首先创建了一个A类的实例,调用了A里面的function,一求11和三的差,一和八的差,这个是没有问题的。因为这个时候我们。我们把这段下面代码先注释注销。11减三,一减八分别调用的是A这个。对象实例的方式一方法,显然这个时候是没有问题,我们执行一下。运行。我们可以看到。结果是正确的,现在呢,他又调用了这个方法。诶,他创建一个B类的实例,他继续去求11减三,他认为什么呢?诶,我用B去掉这个方块一,还用的是我们父类的方一方法,但是他忘了一件事情,方一已经被他重写了。
04:14
对吧,这里他的本意。这里程序员的本意。本意是求出,求出什么呢?11减三的一个结果,同样这边它也是要求出一减八的这么一个结果,但实际上我们发现。因为你不小心重写了父类的方式方法,这个结果肯定是不正确的,我们执行一下。来运行一把。我们可以看到11减三等于14了,一减八等于九了,为什么?就是因为你在这个地方重写了这里。这里他重写了A类。
05:01
A类的方法。这种重写可能是无意识的。对,可能。可能是无意识的,就他不小心。写了,但是代码却出现了问题。对吧,代码出现问题,甚至也有可能是这样子的,它调用的时候。调用的时候,他认为我还调用的是负的呢。因为因为根据我们你是替换原则,你是可以这样替换的,但是因为你这重写了这个你是替换的这个原则,他就不满足了,是这样子的吧。因为他本意是说,诶,那如果说你用我用这个B类去调我,我认为我还调动是他附类的方块一不就对了吗?但实际上因为你重写了这个代码就错了。好,这就是他已经不满足我们的理事替换原则了,那怎么解决这个问题呢?来,我们来分析一把。分析一把。解决方法,我们发现原来运行正常的相减的这个功能已经发生了错误,你原先11减三发生错误,原因就是因为内壁无意中重写了父类的方方法,造成原有功能出现了错误。
06:15
在实际编程中,我们常常会通过重写负类的方法完成吸毒功能,这样写非常虽然很简单,但整个继承体系的复用性会比较差。是这样子的吧,同学们。特别是运行多态比较频繁的时候。这种错误的发生。是容易的。那你是替换原则,告诉我们怎么解决这个问题呢,各位朋友。通常的做法是让原来的父类和子类都继承一个更通俗的鸡肋,或者说更基本的这个鸡肋,将原有的继承关系去掉,采用依赖聚合或者是组合的关系来替代。我给大家改一下,大家就来体会一下好吧,那现在呢,我们对原有的这段代码用理事替换原则来进行一个改进。
07:09
来吧,我这仍然写个pro。Improve。那为了速度快一点呢,我把原先代码粘贴复制过来,我就在原有代码上进一个改进。怎么改呢?首先我创建一个创建一个更加。更加基础的,基础的这么一个积累。OK,那这个鸡肋呢,我们写个贝斯。那我这里把什么呢把。更。把最把这个。把这个更基础的更加。更加基础的。基础的方法和数成员,成员写到哪里呢?写到我们的背实类中。然后下面的这个让A类去继承我们的这个贝斯类。
08:05
看清楚了,好。那紧接着呢,我们这个B类不要再跟A类发生这样的一个竞争关系,而让他也去继承。我们这个类。好,同学们可以看到,当我们这样去改写过后,这个关系。我们的理事替换原则的关系,它就变成这样一种关系了。来看一下一个类图。我给大家画一个类图来体会一下。那大致的意思呢,就是这样子的。我们这儿有一个贝斯类。贝斯类。好,贝斯类里边呢,我们有一个A类。这个A类。他继承了贝斯类,同时我们有一个同学们看到这个B类。那B类原先呢,它是跟A类。实现一个计算,现在呢,我们让他这个关系去掉。
09:02
OK,把B类往上提升。提升到哪里呢?让它成为贝斯类的。一个。一个子类,那如果B类还要用到A类,注意听,如果B类还要用到A类,我们可以采用什么手法呢?就是依赖的,聚合的或者组合的关系来搞定。那有说老师你这个图应该怎么画呢?就说如果是依赖我就这样画一根线。好,如果我这个B类要用到A类,我要用的是聚合,我就这样画一根线。好,如果这个A类的一个对象跟B类进行一个组合,我就画的是这样一根线。哎,这样的关系呢,就。OK了,那这样子就满足我们理事替换原则,因为B和A的这个耦合关系被断掉。耦合关系被断掉,我们让这个闭合类共有的东西提升到贝试类,把它这个级别往上提,它就稳定性就会更高,好,那我们针对这个图形我们来改一改,就按照我这个设计的类图对它进行一个改进,那同学们看我应该怎么写呢?好,刚才基本的东西已经写完了。
10:17
那在B类里面呢,如果注意听,如果B。需要使用到A类的方法,我们使用一个组合的关系,组合是用哪个线呢?就用这个线来描述的。这就是组合,不要着急,同学们,后边关于类图的话,还有他的理解呢,我会专门花一点时间来讲解,好吧?那这边就变成这样一种写法了,来,同学们写一个,我写一个私有的AA等于六一个A。好,这样就形成一个组合。那我把这个解释呢,提升到这个位置来。
11:00
好代码就改完,那如果说同学们看,假如。啊,假如我们我们仍然想使用A的这个方法,我就可以在这里写了public int方式三。对,T at b。它这里面不是一个相减的方法吗?我想用的话,我就return。A return,那我这里面已经有一个A的对象实例,就A点。A。好,那这边就应该认识点A好吧,为什么?因为你这刚好也有个A对不对,点什么方程二把A和B放进去,诶这样就仍然用到了我们A的相关方法,而且呢,A和B的这种关系就没有像原先那么的。怎么样,耦合性那么高了?因为我没有用继承了嘛,我用的是组合的关系,就降低它的耦合度。
12:01
好,那当然代码改动起来也就比较easy了,你比如说现在因为我我现在在这里改动了以后呢,同学们知道。因为我这个B类跟A类就没有任何关系了,那调用者可能也很清楚的知道,这里面不会再有相减的方法了。为什么呢?你你想这个道理,你想这个道理,因为你你在写代码的时候,你会知道B和A没有任何关系,你就不可能再去想说诶我还用这个function,原先那个负类的FUNCTION1求减法不可能了嘛,所以说你这地方肯定在调的时候就很明确了。那我写上这个,因为。因为这个B类。B类。不在。二不再继承。不再继承。继承这个写啊,不再继继承什么呢?A类A类,因此因此调用者,调用者不会不会再认为,再认为方一是求减法了。
13:10
求减法,他不会再这样认为这个问题了,是吧,所以说他在调的时候,它的调用就会很明确。调用完成的功能就会很明确了。那既然很明确,那你不可能再写一个11。减三了,肯定是11加三,是不是这样子就可以了,好这个时候它的本意呢,就变成11加。一加好,再运行一把,我们看代码。我们看代码这个时候肯定不会再有问题,对不对,11加34,一加八等于九,这个也是正确的,那有些同学老师,那我还就想用一下这个相减的方法,可不可以呢?不要着急,不是刚才我们已经有组合了一个A的对象呢。啊,那这个就很简单了,如果我一定还要用。
14:00
还可以用组合。使用组合。组合仍然。仍然可以使用到什么呀?A的相关方法。对不对,相关方法只是这个耦合性呢,就B和A的耦合性会降低,那我再写一个。好,那这个地方我们写个11减三。等于。那这个时候你掉的时候肯定是掉到半成山了嘛。对不对,把11写进去,把三写进去,好这个时候。本意就是求11减三。而且呢,我们用的是A的相关方法,我们执行一下运行之,我们发现11减三呢,等于的是八,完全的OK,好,同学们,通过这样一个小小的案例呢,我相信大家可能对李斯替换原则有一点认识,对不对,有一点认识了。那当然了,我们讲过要深刻的理解这些原则呢,还需要我们在后面讲设计模式的时候,还要加强对它的理解,还要加强对他理解好的,那这个就是我们理事替换原则的内容,现在呢,我把呃刚才讲的内容做一个简单的整理好,打开我们笔记,我们来看一下。
15:17
刚才讲的理事替换原则有哪些内容?看一看。呃,理事替换原则我们是怎么讲的呢?来看一下。找一个。首先呢,我们先阐明了。这一个继承给我们带来的好处,同时呢,也会给我们带来一些弊端,我们先做了一个分析,也就是说继承这个呢,虽然好,但也有可能带来问题,是这样子的吧。他带会带来什么问题呢?我们在这里看到了。它继承给我们带来的便利的同时也带来弊端,它会带来入侵性。所以说在有很多编程里面呢,你会看到有很多人,他更多的喜欢是用更加抽象的一种方式来处理。
16:07
对不对,比如说用接口编程呢,或者是组合呀,聚合的关系来解决。所以说,嗯,这是继承带来的问题,那我们如何去正确使用继承呢?就提出了理事替换。这个理事替换就在这提出来了。OK,那紧接着我们就对理事替换原则做了一个基本的介绍,说了四点。我们来整理一下这个讲解的内容。那么理事替换原则的这四个点是哪四个点呢?我们来捋一捋。来捋一捋这个思路。首先第一个。呃,是谁提出来的?是麻省理工的一个姓李的一个女士提出。然后呢,他这个李斯替换原则,它需要我们。达到这样一个效果。什么效果呢?所有引用基类的地方必须能够透明的使用其指类对象,他要达到这样效果。因此理斯替换原则呢,它其实要求我们尽量的不要去改写负类的方法。
17:12
啊,当然有些同学老师,那我就要改,就要改的话呢,你试听完就告诉我们,我们可以通过聚合组合来解决这样的问题,刚才我们就是用这个方法来处理的,还有印象吧。好,这个基本的讲完了以后,我们就给大家看了一段程序,引起了同学们对这个问题的思考。那这段代码。也有问题的代码呢,是在这写的第一个案例。对吧?好,我们先把这段代码给大家放到表格里面去。从这里面我们我们看出因为你误写了一个方法导致程序的问题,所以说我们紧接着对这一个理事替换刚才的那个方案提出了一些建议和。
18:01
改进的方,改进的一个111个想法。我们写到这来。那怎么来做的呢?我们提出了解决方法。我们提出了一个解决方法,来看一下怎么来做的。怎么来做的。我们提出。让原有的父类和子类继承一个更加通俗的积类,将原有的继承关系去掉,采用什么呢?诶采用的是依赖聚合或者组合的关系来搞定它,好,所以说我们这边就有一个改进方案。改进方案。那么改进方案这边呢,我们首先先画了一个类图,还有印象吧。这是我们。画的一个类图。诶,这个类图重新来一下啊,重新来一下。这个这个类图。哦,诶这个类图怎么。来,我把这个类图截一下。
19:01
OK。这是一个类图,那对应的代码在哪呢?我们把代码也拿过来,这个放小一点好看啊,来代码实现。代码实现,那代码实现我仍然是放到一个表格里边是吧。在哪里呢?就在刚才老师写的这段代码里面去的。体现出做了一个更加基础的积累,然后呢把他们都去继承贝斯,呃,要用到的话呢,我这里用了一个组合关系。来,同学们,我把它放在我们代码中。各位同学,那关于我们李四替换原则,就先给同学们介绍这些,大家要好好去理解一下。
我来说两句