找回密码
 申请新用户
搜索
热搜: 活动 交友 discuz
查看: 6718|回复: 0

基于对象和面向对象编程范式辨析和主流编程语言中的应用

[复制链接]
发表于 2008-6-12 14:26:30 | 显示全部楼层 |阅读模式
转自:http://blog.csdn.net/shendl/archive/2008/06/09/2525785.aspx
前言
         本文的目的是想告诉大家,为什么C++的模板这么强大。为什么Ruby的Duck Typing(像鸭子那样编程)这么强大!






基于对象和面向对象编程范式
关于基于对象和面向对象编程范式,我有着不同于传统的理解。我认为我的理解更能体现出这2个范式的本意。

基于对象,就是使用类封装操作和操作依赖的数据。用类来表示一个概念。类的公共成员,包括函数和数据,就是类的接口,也叫作抽象数据类型(ADT)。

面向对象,就是使用类的接口实现机制来表示操作。一个接口使用一组相关的公共函数代表一个概念的操作。一些类实现这个接口。这个实现类可以互换。
在使用中,使用接口的指针或者引用来调用对象。具体的对象是接口的某个实现类。可以不改变代码,仅仅改变实际的对象来实现动态修改系统的行为。
这就是“动态多态”的能力。
面向对象的动态多态能力,使抽象能力比函数更进一步。
动态多态,在实现中是使用了“虚函数”机制来实现的。
        对象指向的本类的虚函数表来查得真正需要调用的方法。

语言特性对比表
                      C++       Java       .NET     Ruby            
类型           强类型     强类型   强类型    强类型
静态/动态       静态   静态检验类型动态解释执行   动态
支持面向过程   是         否         否        否
支持基于对象   是         否         是        是
支持范型       否         是          是       否
支持模板       是         否         否         否




C++通过抽象基类来作为接口,通过对抽象基类的继承来实现这个接口。
Java和.NET都提供了Interface接口类型。实现接口的类实现了这个机制。
所以说,C++,Java,.NET都支持面向对象的编程范式。特别是java,它只支持面向对象(也就是动态多态)这一种编程范式。其他一概不支持!

动态类型语言,如Ruby,JavaScript都没有接口。为什么呢?
考虑一下,动态类型语言尽管有类型。但是变量都是没有类型的。如
//伪代码
Class Dao1{
   Public void save(model){
     //保存数据
}
}
Class Dao2{
   Public void save(model){
     //保存数据
}
}

Class Service{
   @dao;
    Public void save(model){
       this.dao.save();
}

}
//调用代码:
New Service(new Dao1).save(model);
New Service(new Dao2).save(model);


这里,Dao1,Dao2这2个类需要实现一个共同的接口吗?
动态类型语言中,尽管对象是有类型的,但是变量(实际是指向对象的指针)是没有类型的。Service类的变量dao可以是任何类型!只要那个对象所属的类型有Public void save(model);这样签名的函数即可!
动态类型语言中,根本不需要Java等静态语言中的接口的概念。这就是动态类型语言著名的Duck Typing“像鸭子一样编程”的理念。
         Java这样的静态类型语言当然也有自己的优点。那就是通过强制实现接口。可以保证程序员不会因为笔误而调用错误的类型。
         但是,在实践中,动态类型语言的Duck Typing却是更加灵活,更胜一筹!

动态语言既然没有接口,那么它们调用的方法,也就是该类的方法或者继承的方法,就不需要虚函数表,也就不是面向对象的“动态多态”机制了。
Ruby,JavaScript的“多态”机制,是“动态基于对象”的机制。
根据我的定义标准,Ruby,JavaScript等动态类型语言是“基于对象”编程范式的语言。是“动态基于对象”的编程语言。而非面向对象编程语言。

可能你会说,Ruby,JavaScript 都有“继承”的能力,怎么能说它们不是面向对象编程语言呢?
“继承”,只是一种代码重用机制。和编程范式这样的设计问题根本答不上边。甚至,我反对大量使用继承来重用代码(少数特殊情况除外)。我们应该使用“组合”来重用代码。
因为继承会造成类和类之间的实现依赖。而组合就不会有这种依赖关系。我们只要写上一些通道代码就可换取类和类之间的解耦。

好了,现在再让我们看看C++的基于对象的编程范式。
C++的基于对象,就是设计一些类,把函数和函数需要的数据封装在一个类中。但是,如何实现真正的ADT(抽象数据类型)呢?
这样:头文件代表抽象数据类型。实现文件中提供定义。如果一个抽象数据类型需要多个实现呢?
我们为一个类提供几个实现文件。用哪一个就提供哪一个版本。这样显然非常繁琐。事实上也没有人会这样编程!

那怎么办呢?难道C++这样的静态类型语言的“基于对象”编程范式,注定就不能实现多态吗?C++的模板机制解决了这个问题!(在没有彻底搞懂模板之前,我一直用面向对象编程范式使用C++,因此对C++是怨声载道!)
如:
//伪码
Template<tyepe TDao >Class Service{
Private:
   TDao* dao=new TDao();
Public:
    Void save(Model model){
     This->dao->save(model);

}
}

//使用
   Model* model=new Model();
   Service<Dao>* service=new Service<Dao>();
   Service->save(model);

    假设Dao这个类有Public:
    Void save(Model model);这样签名的方法。

    Void save(Model model)这个函数就是TDao这个抽象数据类型(ADT)公布的方法。
任何类只要有这样的方法,就满足TDao这个ADT,就可以在Service模板类中使用!

     对照上面Ruby的伪码,我们可以发现:
1,C++的“模板支持的基于对象”的编程范式,仅仅比动态基于对象语言多了模板参数类型的声明。
而且,C++可以直接在模板类内部实例化类型。真正的类型只有在编译时才指定。而动态基于对象的语言因为没有代表类型的符号,不能实例化未知的类型。
2,C++的“模板支持的基于对象”的编程范式,指定了模板参数类型,也就是在编译时需要验证类型。这就比动态基于对象的语言多了编译时静态验证类型这一道关卡,更加安全可靠。
   

C++中模板之所以伟大,正是因为它是静态语言中支持基于对象编程范式的银弹!
C++的“模板支持的基于对象”的编程范式,令C++拥有了与Ruby等动态基于对象编程语言的多态能力相比肩的顶级语言!


总结
基于对象和面向对象编程共有三种范式。它们提供了强大的动态或者静态多态能力,使用它们编程,将令你的程序面向抽象,易于更换。
1,“模板支持的基于对象”的编程范式。这种编程范式适用于静态类型的语言。提供了静态多态的能力。典型的如C++。
模板不同于范型。模板是一种编译时的代码生成机制。而泛型是对模板的模拟。在java和.net中都使用类型转换机制而不是源代码生成机制来实现。
我认为模板优于范型。.NET的范型实现的要比Java好。.NET中可以使用new()关键字实现在范型类中创建未知类型的对象,而java中不可以。
“模板支持的基于对象”的编程范式实现了编译时静态的多态。具备了强大的静态多态能力。而且生成的代码运行速度快。
缺点是,如果写得不好,容易发生源代码扩张的问题。

2,“静态类型语言”的面向对象的编程范式。这种编程范式适用于静态类型的语言。提供了动态多态的能力。典型的如Java,NET。
使用接口和实现接口的技术,实现了动态多态。并且可以利用静态类型检验的优势,进行更加完善的类型安全检查。
    C++也具有进行这一编程范式的能力。但是,C++对于这一编程范式的支持并不是很好。因此,C++编程中,应该优先使用“模板支持的基于对象”的编程范式。然后再考虑使用“静态类型语言”的面向对象的编程范式实现多态。

3,“动态类型语言”的基于对象的编程范式。使用Duck Typing“像鸭子一样编程”的编程理念。这种编程范式适用于动态类型的语言。它们有类型,但是变量不确定类型。典型的如Ruby。这也实现了动态的多态能力。
您需要登录后才可以回帖 登录 | 申请新用户

本版积分规则

守望轩 ( 湘ICP备17013730号-2 )|网站地图

GMT+8, 2024-4-20 22:01 , Processed in 0.023106 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表