注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天地不仁,以万物为Googol!

天行有常,不以物喜,不以己悲……

 
 
 

日志

 
 

最小接口与人本接口

2006-10-21 20:24:38|  分类: 积累 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

关于库的接口,有史以来都提倡使用最小化接口的设计原则,也就是指一个库应该提供足够操作这个库的一组必不可少的接口,同时,这些接口完成的功能相互独立,互不耦合。至于更复杂的功能,则由使用者通过对这组最小接口的组合完成。原因是,计算机的资源是有限的,库的体积越小越好,只提供一组最小接口,无疑可以将库的设计最小化。

 

但是,实际上人在真正使用库时,目的很少是其最小接口提供的功能,而是将这些接口组合后的某项更强大的功能。比如dvd播放机,其机器提供盘片出仓,入仓,检查盘片内容,播放,暂停,快进,快退等最小接口,但大部分时间,人们使用dvd机的目的只有一个——看dvd。

 

于是,为了简化,目前几乎所有的dvd机都支持在将盘片入仓后直接播放到片尾的功能,也就是对入仓的行为做了扩展:

void expandEjectIn()

{

    EjectIn();

    if (checkDisc() != DVD)

    {

        return;

    }

    play();

    waitUntilEnd();

    stop();

}

 

这种以人的使用目的为目标,设计出的接口,就是人本接口。

 

由于现在在某些领域,计算机资源相对宽裕,因此,很多库的提供者开始抛弃原有的最小接口原则,转而提供人本接口。据称现在非常火热的Ruby,在其list类中提供的接口就是人本接口。

 

关于Ruby,由于民族原因,我没有多做接触。不过,C++领域也存在着人本接口和最小接口的争斗。比如,最著名的库stl中的vector的接口。

 

stl库在设计之初,就是以最小化接口为目标的。最为明显的就是pop_back的定义:

void pop_back();

 

要知道向量操作中,很少有单独的pop动作,一般这样做之前都要取得弹出的元素。也就是说,一般使用中的形式是:

STH sth = sthVector.back(); //back操作取得元素

sthVector.pop_back();

 

而VC中的stl,就擅自修改标准,将pop_back的实现改为:

Type pop_back();

 

这样,之前那段代码就可以简单的写为:

STH sth = pop_back();

 

由于C++语言的因素,在使用中,VC版的实现也可以单独使用,其效果与stl版一样。这也是为什么VC这样做却没有人明确反对的原因。但是,效果真的是一样的么?

 

第一,程序不可移植。因为VC的实现不是标准实现,使用了pop_back()的返回值,将使程序无法移植到别的C++编译器上运行。这个将是最重要的一个不同——你不知道什么时候会把程序给另一个平台(比如linux)用,而那个平台没有VC……

 

第二,效率下降。以标准形式使用VC版的pop_back(),虽然没有保存返回值,但是在函数内部,依旧要对这个返回做处理,也因此降低了效率——为不需要的功能付出了代价。但是,我相信VC在这里会做优化。

 

当然,可以在vector中实现两个类函数:pop_back和get_back_and_pop。但是这样,类的成员将会变得巨大无比,比如那个string。

 

没有更好的办法了么?

 

其实,可以这样,类的成员函数只实现类的最小接口,然后再提供一组操作这个类的非成员非友元函数,封装最小接口,实现为人本接口,并利用命名空间来保护这类函数。比如,vector可以这样实现:

namespace vector

{

 

template <typename T>

class vector

{

    // blablabla....

    T back();

    void pop_back();

}

 

template <typename T>

T get_back_and_pop(vector<T>& arg);

 

}

 

甚至,还可以在vector命名空间中实现如下函数:

template <typename T>

bool judge_empty_then_get_back_and_pop(vector<T> arg);

 

而且,由于命名空间可以由用户扩展,用户还可以自己在这个命名空间里扩充属于自己的人本接口。这个就有点类似于C#中的部分类的概念了。

 

ps 关于C++这种区分函数性质的方法,可以参看Effective C++第三版的Item 2x(具体忘记了……)。

  评论这张
 
阅读(512)| 评论(2)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017