Java在Interface方面的缺陷- -| 回首页 | 2005年索引 | - -Function Signature:新思维

Visibility:两种观点- -

                                      

几乎所有的OO语言都支持可见性(visibility):C++支持class内的成员变量(属性)与成员函数(操作/方法)的可见性;Java/C#除了支持class内的属性与方法的可见性外,还支持class/interface在package一级的可见性。


Visibility存在的目的是什么? 答案是显而易见的:为了信息隐藏。也就是说,visibility提供了class(C/Java/C#),package(Java/C#)一种能够将外部接口和内部实现进行分离的手段。

众所周知,对于一个class,它可以将自己的属性及方法分为3类:
o public:公开给外部的;
o protected:仅仅开放给继承者(子类)的;
o private:完全私用的.

对于private部分,外部和子类是不可见的(invisible); 对于protected部分,只有自己和子类是可见的;而对于public部分,对所有的外部实体都可见。

但不同语言对于这种机制的看法并不一致。C++在此问题上的观点是:即使一个成员变量/函数是private的,它对于外部和子类仍然是可见的,只不过是不可访问的。所以C++并不称此机制为visibility,而是Access Privilege。

从某种意义上说,Access Privilege是visibility的子集。因为既然都不可见,又怎么可能去访问它呢?但正是因为C++缩小了这种机制的语义范畴,导致其对于信息隐藏的意义在很大程度上缩小了,尤其在继承的时候。

比如,class B想继承自class A,如果把这种机制看作visibility,则它只可以看到class A的public和protected部分。所以,它可以使用这些部分并扩展其功能。在扩展功能时,它就可以使用除了那些可见部分已使用名字之外的名字,而不用担心引起任何冲突。

但对于C++,即使一个成员函数被定义为private的,但对于子类而言,这个成员函数仍然是可见的,只不过子类不具备访问它的权限。但你可以改写它以实现多态。比如:

class Base
{
public: void foo()
 { cout << query() << endl; }
private: virtual int query() const
 { return 0; }
};

class Derived: public Base
{
private: int query() const
 { return 10; }
}

int main()
{
        Base* base = new Base();
        Base* derived = new Derived();
        base->foo();
        derived->foo();
}

从执行结果,你可以看出:query虽然在Base中是一个私有成员函数,但在Derived中,你仍然可以看到它并改写它。

我们再看一段对应的Java实现:

class Base
{
  public void foo()
  { System.out.println(query());}

  private int query() { return 0; }
}

class Derived extends Base
{
   private int query(){ return 10; }
}

public class Test{
   public static void main(String[] args)
   {
       Base base = new Base();
       Base derived = new Derived();
       base.foo();
       derived.foo();
   }
}

由于方法query在Base中是private的,所以Java会认为在Derived中定义的方法query和Base中的query一点关系都没有。执行上面的程序,会看到,调用2个类的foo方法得到的结果是一样的,也就是说,在Dervied类中的query方法根本没有实现多态。

但如果你把Base中query方法的可见性改为public或protected的,那么这个query方法对于Derived就是可见的;此时,两个类中的query方法就有了关系。如果你仍然指定Derived中的query方法为private的,Java就会认为你缩小了query方法的可见范围(由此会产生问题)而给出编译错误。 所以,此时你也必须将Derived中的query方法的可见性改为protected或public的(你可以增大其可见范围)。此时,重新运行上面的程序,就会发现query已经实现了多态。

另外,如果你仅仅将Derived中的query方法改为public/protected的,Java仍然认为两个query之间没有关系,仍然无法实现query的多态。

所以,将这种机制看作Visibility,还是Access Privilege,会很大程度的影响语言的设计、以及设计师/程序员的使用。我个人对此问题的结论是:从面向对象的概念本身来看,Visibility比Access Privilege更加自然和直观。

- 作者: 上帝没发笑 2005年01月31日, 星期一 04:29 加入博采

Trackback

你可以使用这个链接引用该篇文章 http://publishblog.blogchina.com/blog/tb.b?diaryID=650131

回复

评论内容: