开闭原则。比如说有一个打印机的接口Printer,三个不同的打印机类HP、Epson、Canon实现了打印机接口的打印方法print(),在Output类中有类型为Printer的变量p。不管系统与那种类型的打印机相连,输出时都调用p.print()方法。而p的具体类型在运行时由系统确定。我只想问怎么理解“p的具体类型在运行时由系统确定”这句话。系统运行了是怎么确定p的具体类型的?希望各位大师指点一下,举个例子或是提供关键点的代码更好。十分感谢!
“p的具体类型在运行时由系统确定”
上网查查“虚函数表”就明白了。
"p的具体类型在运行时由系统确定"
"由系统确定"说明p的具体类型在编程阶段是无法断定的,比如说,公司的打印机经常换品牌并且打印机是通过配置文件配置的,你的程序需要读取配置才知道要使用哪一种类型的打印机,使用你程序的人也只需要修改配置文件来决定使用哪一个类型的打印机。所以说"由系统确定"。
运行时,是怎么确定打印机类型的? 以Java为例:
由于打印机类型由配置文件来决定,那么在编程的时候就不能针对具体打印机类型进行编程,而应该针对打印机接口进行编程,因为无法断定配置里配的是哪种类型的打印机,下面三种情况都有可能:
Printer p = new HP()。
Printer p = new Canon()。
Printer p = new Epson()。
对于p这个变量,p的静态类型在编译期间就可以确定了。调用print方法时,会进行动态的方法连接,连接到具体类型的打印机上的print方法,这是面向对象的一个特征:多态。
也反映了面向对象的一个设计原则:面向接口编程
先占个坑,明天有空过来谈谈对这个问题的看法。
我来了!撒花~撒花~
不知道我是否理解对了楼主的问题,暂时就我所理解的来说说自己的看法,重在交流嘛~~
为了节省时间和篇幅,下文用OO来代替“面向对象”,请自行在大脑中运行replace()
。
首先,
开闭原则
是OO编程思想中的一个重要原则,既然是OO领域的,自然大前提是针对OO语言下的编码实践。同样,OO语言为我们提供了3大基本特性:抽象、封装、多态
。这是所有OO语言所共通的,如果某个语言没有提供这3大特性就声称自己是OO语言,毫无疑问会被人一巴掌糊一脸翔!能够在运行时动态确定对象的类型是一种语言实现
多态
的前提。同样,如果一种OO语言无法在运行时确定对象的类型就说自己实现了多态,毫无疑问会被人一巴掌糊一脸翔!一种OO语言如何实现多态,根据语言的不同方式也不同。但总体来说,必然需要定义某种数据结构,其中记录着每个运行时对象的相关信息(对象的类型只是其中之一)。每个对象在创建时都会同时生成该结构的实例并且用对象的相关信息填充其中的字段。这样一来,只需查询该结构就可以获得对象信息了。这是语言实现层面的东西,与我们程序员无关,我们只需要知道OO语言提供了这种功能就好。
-
下面再来谈谈
打印机
和print()
的问题。我想Output
类必然具有以下结构:Printer printer = a_printer_instance; void output(content) { printer.print(content); }
其中,实际的打印机对象
a_printer_instance
是在运行时创建的,虽然创建方式可能不同(直接创建、通过工厂、反射、外部注入等等),但可以肯定的是,Output
对象所拿到的是一个实实在在的打印机对象,是3种打印机类型之一。而且前面说过,只要存在一个对象,OO语言就能够获得它的运行时类型。所以等到执行output()
方法中的打印语句时,必然可以找到正确的print()
方法实现,进而正确打印出内容来。 仅就多态这一点来说,实现起来并不复杂。用
C
也可以很容易地实现(使用函数指针)。OO比面向过程更先进的地方体现在它同时实现了抽象、封装、多态
三种特性,从而简化了软件开发过程。
不知不觉写了一大段,到此住笔吧~共勉~
我估计你理解歪了
p的具体类型在运行时由系统确定
不是说系统运行起来后,里面有个啥机制帮你确定p的具体类型
实际上就是写代码调用Output()方法时自己决定,调用这个方法时,传递的p参数对象,是一个实现了Printer接口的类实例就行了
接口是起规范作用的。
比如windows有打印功能,那么它只会对打印这个功能做出约束,不会去管某个具体型号的打印机,这么多型号的打印机,我都不认得,只认得print()
方法,只知道它能打印东西,管你们内部怎么先进,要通过我工作,都按照我的规范来——必须实现一个print()
方法,你要是鼠标其他的,必须按照其他相关的接口来。
什么?你注册了打印机,但是没有print()
接口?
报个错~
好。
现在我要用windows打印这个答案,
chrome调用打印API,
windows开始找能使用的打印机设备,
好,现在有HP、Epson、Canon这三个可以用,用户选择哪个打印机,系统就去调用它的print()
方法(期间会有驱动加载)。
就完成了。
至于打印机怎么打印出来东西的,管他呢。
public interface windows_print {
public void print();
}
当你选择的某个打印机时候,这个打印机的对象就会生成出来,GUI的好处。
代码实现方法很多
直接创建、工厂模式、注入等等,就是你的那个p。
public class HP implements windows_print {
public void print() {
//code
}
}
output类里调用的print方法,是个接口回调技术,你用output这个类里的print方法时,必定要传new HP() ,new EpSon() ,new Canno()这些对象中的一个,至于是哪一个,则要看你业务需求来定。比如:
Output类中定义:
print(Printer p)
{
p.print();
}
需要调用的地方:
Output out=new Output();
Out.print(new HP());
它这句话意思我理解是 实例化时候它的类型 取决于谁实现了print 。hp实现了接口 那么系统运行时 必然new出来的类型是hp。
接口是定义一个规范 具体实现由实现它的系统决定
你可以单独编写许多怎么使用打印机的代码 即对obj.print的调用 然后把打印机本身作为一个可变项 即obj不是这些代码直接通过new构造的 可以是 通过 函数参数 成员变量等 具体的对象在调用这些代码时给出 比如传递给函数的参数或者赋值给相应的变量
至于内部实现 面向对象语言在设计对象的数据结构时会同时记录对象所属的类(或者原型)以及对象所属的继承链(或接口、默认方法响应器等) 在对象传递过程中 不同的代码执行中可以得到各自需要的信息