当前课程知识点:面向对象程序设计(C++) > 第五讲 找到对象,确定接口 > 5.5 变与不变:多态的威力 > 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的时候
我也可以用同样的方式去调用它
这样当我加入新的功能的时候
我就可以避免
程序造成大规模的修改
因为我用的都是接口类
因为你这实现类只不过是
我这个接口类的又一个特例而已
如果我这个地方
我引用的
直接引用的就是实现类
就是这个特例
那我就要对这个特例进行修改
而现在我引用的并不是特例
引用的是这个概念
引用的是这个接口类
那你只要把这个特例
做一下替换就行了
这就是我们面向对象编程一个
很重要的一个原则
或者说我们实现开闭原则的
一个很重要的实现的道路
就是针对接口编程
而不要针对实现编程
我们先要考虑清楚接口是什么
把接口定清楚
然后针对这个接口
去构建我们的设计体系
最后再去对这些接口
进行一一实现
这样我们的程序
才具有更好的灵活性
更容易符合
我们前边说的开闭原则
-1.0 课程定位、教学内容
-1.0 课程定位、教学内容--作业
-1.1 编程环境与工具
--源程序拆分
-1.2 main函数的命令行参数
-作业一--作业
-2.1 变量定义
--变量定义
-2.2 变量的初始化、类型推导与基于范围的循环
-2.3 函数重载
--函数重载
-2.4 函数参数的缺省值与追踪返回类型的函数
-2.5 类的定义
--类的定义
-2.6 类成员的访问权限与友元
-第二讲 基础语法(1)--作业二
-3.1 构造函数析构函数
--构造函数析构函数
-3.2 赋值运算符重载
--赋值运算符重载
-3.3 流运算符重载
--流运算符重载
-3.4 函数运算符重载
--函数运算符重载
-3.5 下标运算符与自增减运算符重载
-3.6 静态成员与常量成员
-3.7 对象组合
--对象组合
-3.8 移动构造函数
--Video
--Video
-3.9 default修饰符
--Video
-第三讲 基础语法(2)--作业三
-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
-期末考试--作业