当前课程知识点:面向对象程序设计(C++) >  第五讲 找到对象,确定接口 >  5.5 变与不变:多态的威力 >  Video

返回《面向对象程序设计(C++)》慕课在线视频课程列表

Video在线视频

Video

下一节:讨论

返回《面向对象程序设计(C++)》慕课在线视频列表

Video课程教案、知识点、字幕

刚才我们说了

咱们这个设计了之后

这个旋转填充这个类

这个matrix类

当填充方式发生变化的时候

我们只要修改

这个findposition就行了

但是大家回想一下

咱们之前说过

我们是希望我们的类

或者说我们已有的代码

是尽量不要被修改的

我们的开闭原则不就这么回事嘛

所谓开闭

开是我们的这个程序

或者说我们的代码

对各种新的功能是开放的

可以加入新的功能

可以适应变化的

闭一方面是不要修改原有代码

另一方面也指的是

尽可能的不要动原来的属性

因为我们都知道

这个代码

什么样的代码是最好的代码

就是那些经过千锤百炼的

用过很长时间的

我们都已经上线跑了十来年的系统

它是经过这种千锤百炼之后

咱们可以认定它是没有问题的

那么这样的代码我们尽量不要去动它

在这个里面我们就是说

这个matrix这个类

当我们需要去

改变它的填充的方式的时候

我们有没有一个办法

不用去改这个matrix这个类呢

因为我们实际matrix类大部分都不用动

唯一需要改变的

就是这个findposition这个函数

好了

我们看到了

之前我们在学这个语法的时候

有一个叫

00:02 :15英 的东西

在这里就体现出它的作用了

我们可以把这个findposition

给它定义为一个纯虚函数

一个virtual findposition

那么这个纯虚函数

它的实现就被推迟到

matrix这个class它的子类里边去

当你定义了一个

顺时针填充的matrix的时候

你就可以顺时针填充的方式

就是我们刚才那个方式

去实现这个findposition

当你定义一个

行优先的填充的这种matrix时候

你又可以以行优先的方式

来实现这个matrix

我们看这里面

看到了matrix我定义了一个virtual的一个

findposition这么一个纯虚函数

下面我顺时针的时候我是一种实现

而行优先的时候则是另外一种实现

当调用的时候

我这个main函数里调用了matrix fill

然后这个fill

又去调用这个findposition

当调用这个findposition的时候

它就可以根据

你当前这个类到底是什么

你当前这个对象

是顺时针填充的matrix

还是行优先填充的matrix

去调用相应的findposition

这样我同一个matrix

它的不同子类

就体现出了不同的填充顺序

从另一个角度来讲

这又是一种

叫做模板方法的设计模式

在这个模板方法这个模式里边

我这个抽象类

就是刚才我们说matrix这个副类

它定义一个算法类不变的骨架

就是刚才我们说的那个

循环 从1到N平方的那个循环

然后针对每一个

N去获得它的position

然后再position给它

对应的位置写成数字

然后算法其中有一部分细节要修改

刚才那个findposition

它是要被修改的

这个需要修改的细节呢

需要改变的细节呢

放到实现类里面去

放到子类里面去

子类以这个override重写的方式

就是这个虚函数重写的方式去实现它

那么在使用的时候我调用

直接调用这个抽象

调用matrix类的时候算法骨架

就是刚才我们那个fill

然后这个fill再根据需要

调用相应的子类的细节实现

到底你是顺时针填充的

findposition

还是行优先的findposition

根据你当前对象到底是哪个类

来决定

这时候我换一个新的实现类

那我比如说原来是行优先的

我换成了顺时针的

那么新的算法步骤细节

就是那findposition变了

我这个fill过程也会发生变化

它都是把所有这些数都填进去了

但是它填的位置就不一样了

这也是骨架和细节之间的关系

最后我们看一下这个

这个是对模板方法的一个UML描述

它实际上是这样子的

首先有一个抽象类

或者我们有的时候又管它叫接口类

这个抽象类

它定义了一个 00:06:11英

这个实际上就是我们刚才算法骨架

这个算法骨架的实现过程中

会调用几个算法细节的函数

我们看到了这里面

从00:06:29到这引出来一条虚线

在右边显示出00:06:33的这个方法

是如何实现的

在实现过程中它调用了另外两个函数

这两个函数就算法了一些细节

然后它下面又出现了一个实现类

我们注意到刚才那个抽象类的里面

它的类名和它的虚函数

都是用斜体来表示的

而下面实现类里面

类名和实现这个函数

都是由没有斜体

就是正体来表示的

然后这个实现类

和抽象类之间有一条线连接

同时有一个小三角形

这个三角形和这个线

代表着类和类之间的继承关系

换句话说就是下面这个实现类

是上面抽象类的一个子类

我们有的时候对这种类的继承

又把它叫做接口类和实现类

之间的一个关系

从这里我们实际上

又可以总结出这么一个原则

我们在设计面向对象程序的时候

我们并不是一上来就考虑

这个程序是怎么实现的

我们一般情况下是先通过抽象

抽象出一些抽象的概念来

比如像刚才我们说的这个matrix

它是一个概念

这个概念它有一系列的接口

所谓接口就是什么

我要实现一些什么东西

这概念它应该具有哪些功能

比如像咱们刚才说的matrix

它应该有什么功能

有fill 有输出

还有findposition

其中findposition是一个抽象的

要被继承的东西一个虚函数

然后我们在针对这个接口

去相应的实现它的实现类

比如说我们刚才说的那个

顺时针填充的

什么行优先填充的

这都是matrix这个抽象类

这个接口类的一些实现类

这样当我们这个接口类的

我们对应这个概念的实现细节

发生变化的时候

我们可以通过实现新的实现类

来适应这种变化

返过来呢

在我们使用这个概念的时候呢

我们不直接去使用这些实现类

而是用这个接口类引用这概念

这样我们实际上

就像刚才那个例子里面

我们总是用matrix来实现fill

实现它的输出

而不能直接调用顺时针的matrix

或者行优先的matrix

不是调用那些东西

而是直接用抽象的matrix去调用

这样当你加入了新的matrix

比如说我又加了一个

列优先的matrix的时候

我也可以用同样的方式去调用它

这样当我加入新的功能的时候

我就可以避免

程序造成大规模的修改

因为我用的都是接口类

因为你这实现类只不过是

我这个接口类的又一个特例而已

如果我这个地方

我引用的

直接引用的就是实现类

就是这个特例

那我就要对这个特例进行修改

而现在我引用的并不是特例

引用的是这个概念

引用的是这个接口类

那你只要把这个特例

做一下替换就行了

这就是我们面向对象编程一个

很重要的一个原则

或者说我们实现开闭原则的

一个很重要的实现的道路

就是针对接口编程

而不要针对实现编程

我们先要考虑清楚接口是什么

把接口定清楚

然后针对这个接口

去构建我们的设计体系

最后再去对这些接口

进行一一实现

这样我们的程序

才具有更好的灵活性

更容易符合

我们前边说的开闭原则

面向对象程序设计(C++)课程列表:

第一讲 课程简介与编程环境

-1.0 课程定位、教学内容

--课程定位与教学内容

-1.0 课程定位、教学内容--作业

-1.1 编程环境与工具

--程序结构与编译链接

--源程序拆分

--多文件编译链接的方法

-1.2 main函数的命令行参数

--main函数的命令行参数

-作业一--作业

第二讲 基础语法(1)

-2.1 变量定义

--变量定义

-2.2 变量的初始化、类型推导与基于范围的循环

--变量的初始化、类型推导与基于范围的循环

-2.3 函数重载

--函数重载

-2.4 函数参数的缺省值与追踪返回类型的函数

--函数参数的缺省值与追踪返回类型的函数

-2.5 类的定义

--类的定义

-2.6 类成员的访问权限与友元

--类成员的访问权限与友元

-第二讲 基础语法(1)--作业二

第三讲 基础语法(2)

-3.1 构造函数析构函数

--构造函数析构函数

-3.2 赋值运算符重载

--赋值运算符重载

-3.3 流运算符重载

--流运算符重载

-3.4 函数运算符重载

--函数运算符重载

-3.5 下标运算符与自增减运算符重载

--下标运算符与自增减运算符重载

-3.6 静态成员与常量成员

--静态成员与常量成员

-3.7 对象组合

--对象组合

-3.8 移动构造函数

--Video

--Video

-3.9 default修饰符

--Video

-第三讲 基础语法(2)--作业三

第四讲 基础语法(3)

-4.1 继承

--Video

-4.2 函数重写

--Video

-4.3 虚函数

--Video

--Video

-4.4 自动类型转换

--Video

-4.5 禁止自动类型转换

--Video

-4.6 强制类型转换

--Video

-4.7 函数模板

--Video

-4.8 类模板

--Video

-4.9 成员函数模板

--Video

-4.10 模板特化

--Video

-作业四--作业

第五讲 找到对象,确定接口

-5.0 引言

--Video

-5.1 从FOP到OOP

--Video

-5.2 对象在哪里

--Video

-5.3 接口在哪儿

--Video

-5.4 实现接口

--Video

-5.5 变与不变:多态的威力

--Video

第六讲 算法横向拆分,分离步骤

-6.0 引言

--讨论

-6.1 从负载监视器的设计开始

--从负载监视器的设计开始

-6.2 接口的分离与单一责任原则

--接口的分离与单一责任原则

-6.3 委托与接口的进一步分解

--委托与接口的进一步分解

-6.4 分离不同层面的可变性

--分离不同层面的可变性

第七讲 算法纵向拆分,分离表示

-7.0 引言

--Video

-7.1 迭代器

--Video

-7.2 迭代器的实现

--Video

-7.3 迭代器与模板

--Video

-7.4 算法与数据的解耦

--Video

-7.5 抽象结构与类模板

--Video

-7.6 函数对象与算法分解

--Video

-7.7 基于模板的策略模式

--Video

第八讲 基于接口组合,应对复杂变化

-8.0 引言

--Video

-8.1 已有资源的组合

--Video

-8.2 适当引入接口

--Video

-8.3 接口不变时的功能变化

--Video

-8.4 装饰

--Video

-8.5 责任的传递与责任链

--Video

-8.X 小结

--Video

第九讲 增加抽象层级,隔离复杂变化

-9.0 引言

--Video

-9.1 通过封装增加隔离、应对变化

--Video

--Video

-9.2 增加抽象层,应对变化

--Video

--Video

-9.3 相互关联对象的创建

--Video

-9.4 示例:自动组卷系统设计

--Video

-9.5 设计思路(上)

--Video

-9.6 设计思路(中)

--Video

-9.7 设计思路(下)

--Video

-9.X 小结

--Video

-课程总结

--Video

期末考试

-期末考试--作业

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。