论坛首页 Java企业应用论坛

关于接口暴露问题的解决思路

浏览 6016 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-04-19  
OO
前一两天在讨论群里,我提出过一个关于接口暴露的问题与群友们进行讨论,后来无甚结果,所以把自己这一问题在这里提出来,希望和大家讨论讨论。

   该问题主要是关于对外接口暴露的问题(此接口并非指java中的interface,而是指用户编程时可使用的接口),例如有一个类的大部分方法是不应该暴露给用户的,然而事实上,因为设计问题,任何一个用户都可以创建该类的实例以至于使用它,虽然在实际当中,可能没有用户会去这样做,不过我认为如果能够尽量避免这种情况应该是最好的选择。但是又该如何避免呢?

   我想这种问题出现的主要原因体现在设计者在对象职责分配上想尽可能的达到分散职责让程序更容易进行维护,这种目的是非常正确的,不过在实现上可能没有注意到接口暴露的问题,导致出现了我所说的情况。在群中讨论的时候,并没有人认同我的看法,也许我是错的,也许我是对的,不过这无关紧要,重要的是能够通过交流发现问题促进进步。

举个简单的例子:

public class TestA{
 public void methodA(){
   TestB testB = new TestB();
   testB.methodB();
}
} 

public class TestB{
 public void methodB(){
……
}
} 


在上面这个例子中,TestA依赖于TestB,而TestB这个类的方法应该是用户不可见,且不能让用户使用的,如果按照上面的方法,用户就可以使用TestB这个类了。

   对于这一问题,我的解决办法是将职责分配到实现类的父类或者接口上,在实现类当中以protected为方法标识,这样做虽然不能完全避免,但是可以尽可能的让客户知道哪些是给他使用哪些是不该使用的。

public class TestA extends TestB{
 public void methodA(){
   methodB();
}
}
public class TestB{
 protected void methodB(){
……
}
}


根据上面这种方式,TestB的方法通过protected进行了隐藏,可以进一步的让用户得知他所拥有的权限,从而就可以很轻易的解决了接口暴露的问题,上面的例子只是为了表达明确,并没有过多的设计,在实际开发当中,TestB更多的是作为抽象类或者是接口的形式出现,这种做法一样达到了对象职责的区分,容易维护,同时也封装了不该外露的接口,而且也可以随时开发给用户使用。在这里我只讲了一个大概的思路,并没有详细讨论如何去做,还需大家一起来参与。

对于这一问题只是本人一家之谈,可能有很多我没有想过的问题,有不同意的朋友欢迎与我讨论。
   发表时间:2007-04-20  
从设计的角度来将,应该暴露只应该暴露的东西,但是楼主的例子还是有些问题,因为如果是classB完全只被classA使用,则完全可以将B作为A的内部类来使用,我们永远不要忘记优先使用聚合的原则。

毕竟继承让我们浪费了一次继承的机会。

实际上这里涉及到两个问题,类隐藏和方法隐藏。

关于类的隐藏可以设计成内部类,前提是只有一个类引用,也就是说该类是私有的。另外可以通过factory的作用达到隐藏具体类创建的作用。
当然如果调用者绕过Factory非要new XXImpl出来则也没有办法。

方法隐藏就是对于public方法的定义要小心,确认是否真正的需要public。

对于设计我觉得定义方法的公开级别比类更加普遍。

0 请登录后投票
   发表时间:2007-04-20  
例子好像有点不合适
classB要让classA用 就已经暴露接口了 。
0 请登录后投票
   发表时间:2007-04-20  
既然TestB只对TestA开放,那么说明两个类的紧密性,那么把这两个类放到一个包里,让方法使用默认修饰,只在本包内使用就可以了。
0 请登录后投票
   发表时间:2007-04-20  
引用

从设计的角度来将,应该暴露只应该暴露的东西,但是楼主的例子还是有些问题,因为如果是classB完全只被classA使用,则完全可以将B作为A的内部类来使用,我们永远不要忘记优先使用聚合的原则。

毕竟继承让我们浪费了一次继承的机会。

实际上这里涉及到两个问题,类隐藏和方法隐藏。

关于类的隐藏可以设计成内部类,前提是只有一个类引用,也就是说该类是私有的。另外可以通过factory的作用达到隐藏具体类创建的作用。
当然如果调用者绕过Factory非要new XXImpl出来则也没有办法。

方法隐藏就是对于public方法的定义要小心,确认是否真正的需要public。

对于设计我觉得定义方法的公开级别比类更加普遍。

可能是我的表达有问题,我所指的情况是在TestB并不仅仅只给A使用的情况下,如果使用内部类隐藏则把整个类都隐藏了,不适合其他类使用,对于使用factory来进行隐藏,可是类仍然存在可被直接使用的问题,能尽量不提供公共的接口就应该避免,当然是在可行的情况下,而非是什么情况都使用继承或者接口实现来处理这一问题。

引用

例子好像有点不合适
classB要让classA用 就已经暴露接口了 。

我所谓的暴露接口是指避免让用户可以直接使用,而classA是必须依赖于B的,但是B则不能够提供给其他人使用

引用

既然TestB只对TestA开放,那么说明两个类的紧密性,那么把这两个类放到一个包里,让方法使用默认修饰,只在本包内使用就可以了。

使用默认修饰并不好,这样就迫使依赖该类方法的其他类必须与该类在同一个包内,导致包可能非常臃肿,这种方式是最不推荐的了
0 请登录后投票
   发表时间:2007-04-20  
这是个有意义的问题, 像C++就有一个 friend 关键字, 用来给特殊关系的类之间开后门. 到了 Java 把这个给去掉了, 我觉得不是因为这个机制完全没有必要, 而是 friend 修饰这么单一级别的划分对实质性问题反而欲盖弥彰, 还不如不要. Java 里似乎是通过默认的 default/package 权限来解决这方面的问题, 同一个包里的类可以互相之间访问任何非private的成员.

不过OO再精练升华以后, 我相信下一代OO语言在这个方向上还是需要点作为的. 可能是在 "代码单元" 之间可以自定义角色, 比如Helper, Client之类的, 根据角色再进一步界定不同成员的访问权限/可见性.
0 请登录后投票
   发表时间:2007-04-22  
calmness 写道


引用

既然TestB只对TestA开放,那么说明两个类的紧密性,那么把这两个类放到一个包里,让方法使用默认修饰,只在本包内使用就可以了。

使用默认修饰并不好,这样就迫使依赖该类方法的其他类必须与该类在同一个包内,导致包可能非常臃肿,这种方式是最不推荐的了


如果两个类有这样的特殊关系,没有理由不把他们放在同一个包里,如果这样包就出现了臃肿问题,那只能说明设计上有问题。
0 请登录后投票
   发表时间:2007-04-22  
或许可以使用private的默认构造方法.那么B类最好不要有默认构造函数要做的事情,或者把初始化挪到init方法里去,或者有参数的构造方法,让别人来调.如果说a也打算用有参数的构造方法的话,那狠一点都放到init里做初始化好了.
主要目的是告诉别人如果你new了我,那么我就报错,你就无法使用我,你要用我就必须换一种方法来创建我.
结合factory的话,应该就更加可行了.
另外我也觉得你如果这么new的话,有必要放到一个包里面.
另外提出我的一个方法:
权限都用包权限,然后要对外开发的东西就用一个代理类公布出去,要调就调代理类好了.去除a和b的耦合比较好.
0 请登录后投票
   发表时间:2007-04-24  
其实design patterns就是为了解决一系列的这些问题。客户端所有的调用都应该通过调用接口来完成,虽然new了不同的实现子类,但是子类的具体实现,客户端是无法看到的。所以楼主的大体思想是对的,我表示赞同。
0 请登录后投票
   发表时间:2007-04-25  
感觉接口通常有两种:

1. 客户接口,主要暴露给客户,供客户方便使用。

2. 实现接口,真正用于实现代码的地方,可供其实现者,客户接口实现者(用来组装)和高级用户使用。

客户接口通常要客户用最小的努力使用到尽可能常用的功能,它的实现一般会去assemble各种实现接口的实现类,所以它很象一个facade.

实现接口才是真正用来封装,复用的。通常实现接口的实现类都写的短小精悍,做最少的事情,把组装的工作留给别人(客户接口实现类)。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics