00:00
开闭原则。我们来看一下开闭原则是一个什么样的内容。首先我们做一个基本介绍,开闭原则呢,叫open closed principle。它是我们编程中最基础也是最重要的一个设计原则。其实同学们要明白一点,我们前面的。各种原则,其实最终都是为了实现这个开闭原则,也就是说达到开闭的这么一个效果。那么什么是开辟原则呢?同学们来看这句话。他说一个软件实体,比如说一个类吧,或者是一个模块,或者是一个函数,它应该对。扩展开放。对修改关闭。那这句话我们第一次听会觉得比较矛盾,是不是?如果我来第一次学,我也觉得很矛盾。什么叫扩展是开放的,但是修改又是关闭的,不是很矛盾吗?你开放,那就意味着你要去修改代码。可能是增加,可能是修改对吧,但是你又说修改又关闭,这不是很矛盾吗。
01:05
他是这样理解同学们,它所谓扩展开放,它指的是什么呢?OK,注意听它指的是对。对我们这个提供方来说,就说提供功能的这一方来说,它的扩展我们是开放的,也就是说它可以增加。内。这是没有问题的。那么它所谓的这个修改关闭,它主要指的是哪一块,要这个修改要关闭呢,是指的使用方。啊,这个是针对就是对我们使用方而言呢,它这个修改是关闭的,换言之就是说当我们有一个功能扩展了。这肯定是要修改代码的,要么是修改,要么是增加,这是肯定的,没有办法避免,但是呢,我增加了一个类,或者是增加了一个功能以后呢,我原先使用的这一方的代码怎么样,并没有做修改,诶这个就是指的扩展开放,而修改关闭的核心含义理解,那也就是说用抽象构建框架,用实现扩展细节。
02:16
这句话。那么我们再来看第三句话,就是说当软件需要变化的时候,尽量通过扩展软件的实体行为来实现变化,而不是通过修改已有的代码来实现变化。就是说尽量是增加一种扩展,而不是修改。注意听这句话啊,是扩展而不是修改,通过扩展。不是修改什么意思,就是说当我们增加一个功能,尽量不是去修改代码,而是增加。这样子呢,会对,因为你修改就意味着比如说你修改了原有的一段代码,可能这一段代码是别人正在使用的,比如说你修改了一段代码,这段代码你确实增加了一个功能,比如说你加了一个分支,但是这一段代码有可能被另外一个类正在去引用或者使用或者依赖,那你就有可能造成你这边的修改,影响我们这边的使用,是不是这个道理,同学们。
03:20
所以说在我们这个开辟原则里面,它还提倡一个什么呢?如果你要增加一个功能,最最好是扩展,比如说我增加了一个类。或者是增加了一个方法,但这个方法呢,因为你是新增加的嘛,你既然是新增的,那肯定对原有的这个系统是不会构成威胁的。因为你新增的肯定没人用过吧,是不是,哎,这就完事了。所以说他说通过扩展而不是通过修改明白好第四一点,同学们注意编程中遵循其他的原则和使用设计目的,最终其实都是为了遵守开辟原则,因此开辟原则其实是我们的核心。
04:00
开闭原则是我们的核心,OK,那如果我们仅仅用语言来描述开闭原则,我相信很多同学听起来比较吃力。那现在呢?我们来看一个史记的案例,加深对它的理解。先来看一段代码,各位朋友。先来看一段代码。嗯,这段代码呢,是这样子的,他说要完成一个画图形的功能。就是我要去画各种图形,那么这个类图的设计呢?别人已经给你了,是这有一个类叫graphic editor,就是用来画图的。用来画图的,那么这里面呢,有一段代码,根据你这个图形的类型不一样,我调用相应的方法来完成绘制。然后呢,这个graph editor呢,它会依赖。呃,Rectangle sharp,还有circle,就是呃句型,还有就是呃圆形,那么这个sharp呢?是sharp是我们的一个图形。
05:06
对不对,是一个图形,那么是一个图形的话呢,这个矩形还有圆形呢,是实继承了这个sharp。好,就是这么一个结构,那对应的代码呢,因为比较简单,我已经写好了,来我们把这段代码拿过来,拿过来过后我们用一用来分析一下这一段代码存在的问题,然后再用我们开辟原则进行什么呀,进行一个改进,这样我们就对开辟原则有比较深刻的理解,来各位朋友打开我们这一个。Edit eclipse,然后呢,我新建一个包包,这个包里面我们讲的是开闭原则,所以叫OCP,就是open close。那我这边呢,就写一个类好吧。写一个类叫OCP,没问题吧,OCP。
06:00
把主方法勾上,然后呢,我把已有的代码先拿过来用一用。嗯,这个test的方法,我这块我就不要了,因为上面有,然后我格式化一下。来,我们看看这一个代码它是怎么来完成的,好,这这是一个,这是这是一个用于。用于绘图的。绘图的累。而同学们可以看到呢,这个里面的代码它是这样完成的,它接收这么一个sharp。然后呢,根据类型来调用不同的方法啊接收。他接收什么呢?接收except对象。OK,但对象可能是他一个子类对象,然后干什么呢?然后根据这个type。Type来绘制。来绘制不同的。
07:00
对吧,绘制。绘制不同的图形。图形没问题吧?那这边是画我们的矩形,这边是画我们的圆形,我就不多说了,然后呢,这边这是一个sharp。萨类,显然这个类呢,它是一个鸡肋。它是一个鸡肋,这个没问题吧,鸡肋。OK,那么这一个有一就一个句型类,它继承了sharp,这边有个圆形类,它也进sharp,然后呢,在构建的时候给它附不同的类型,好现在呢,我们来使用一把。现在我们来使用一下测试。使用。使用看看存在的问题。对,存在的问题是什么?Now,首先六一个graph editor。这个。这个没问题啊,然后呢,我们调用。Graph editor这个对象实例去绘制我们的图形,比如说第一个我要绘制的是一个矩形rectangle。
08:07
然后呢,我们再去调用draw。是,然后呢,再去绘制我们的圆形,没问题吧,同学们好,现在呢,我调用一下,这边我改一个名字叫绘制。绘制,绘制矩形。绘制句型,这边呢,是绘制我们的原型。绘制我们的原形。好,同学们,我们运行一下这段代码。这段代码应该是没有什么问题的,很简单对吧,一个是绘制句型,一个是绘制原型,因为他把相应的对象实例传给draw以后呢,它根据你的这个type类型不同,调用了不同的方法。对不对?第二我不懂这个方法,同学们可以看到它是绘制句型的。这个是绘制圆形的,没问题吧,同学们很简单对不对,绘制我们圆形的。
09:04
那现在的问题在哪里呢?各位朋友,我们来分析一把它存在的问题,来看我的下一个说明。这个方式一的优点和缺点,我们做一个。分析,首先它是有优点的,优点就是比较好理解,简单易操作,就是很容易让我们想到这样去做。但是缺点是违反了设计的OCP原则及对扩展开放扩展,我们刚才讲的是所谓的对什么开放啊,对使对这个提供方。提供方扩展式开放的对使用方。对使用方,使用方。OK。使用使用方对使用方修改是关闭的,那么同学们想当我们给类增加一个新的功能的时候,我们需要尽量不修改代码或者少修改代码,但是问题来了,大家看,如果我们新增加一个新的图形,比如说呃。
10:02
三角形,那么这个时候我们要做什么修改呢?我们发现修改的比较多,我们来演示一下,比如说我增加一个三角形。什么形呢?我们叫三角形,画三角形,三角形。好,来看一下。我们新增一个三角形。新增。画。画三角形的这个类,那可以class。翻。呃,这个是吧。Triangle,然后呢,然后我们继承。在这里面呢,我们按照他的这个方式。我们也去构建,给他写一个构造器,这个构造器呢,我们写成类型为三。那你把这个加进去看啊,这个地方我们扩展功能是没问题的,但是有没有发现。我们首先要在这儿使这个是不是使用方。这个就是我们的使用方。
11:02
因为你使用。我们这一个图形来去绘图的嘛,它你看它它要增加一个什么呢?大家看啊,它要增加,它要绘制。绘制什么呀,三角形。对不对,那我把为了省事,我把这个方法。那个粘贴一份。画出我们的三角形。对不对,那这个地方我们就叫绘制三角形,三角形没问题吧,那你调用的时候是不是这边还要来调一下呀,Graphic editor点坐。C。然后六。我们的一个三角形。那六完了之后,我们再再来运行,我们发现呢,代码是没有问题的。我们看是不是这边少写了一句话呀。哦,忘了。这这哦,这地方没有写,看到没有,是不是这面还要改啊,你看这还没改完呢,If,你看这个改动还是比较大的,对不对,如果它的类型为三,我们调用的是draw。
12:11
我们的三角形。对不对,学angle,然后这边呢,我们仍然把这个S放进去,来各位同学再运行。当我们运行的时候呢,我们发现绘制三角形也就出来了,大家有没有发现有什么问题?我们这边你们有没有发现,首先我们新增三角形,这边代码是做了改进,第二个我们在使用方,因为这是使用方嘛,使用方他修改了,这里还增加了新的方法。显然,这就违背了什么原则,违背了我们的OCP。原则就是你。在我们这一个使用方也修改了,但我们其实是希望修改是关闭的。好,同学们,我们通过一个案例呢,我们可以看到我们现在的这个解决方案其实是不好的,而且呢,我们通过一个案例也看到的确修改代码比较多,那怎么办呢?好,那下一步呢,我们就准备用OCP这个原则,遵守OCP的原则,对我们方式一进行一个改进。
13:19
OK,那改进的代码呢?我们在下一个视频为大家进行讲解。
我来说两句