论坛首页 Java企业应用论坛

优先使用接口而不是类

浏览 3614 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-05-21  
OO

正在研读Joshua Bloch的《Effective Java》一书。书中至少在两条中提到了“优先使用接口而不是类”,一是第25条中的“参数类型优先使用接口而不是类”;另一个是第34条中的“通过接口引用对象”。

 

两条中所提及的例子一个是Map,一个是List(因为此书的作者就是Collection Framwork的作者)

 

Map ht = new Hashtable();

 

String value= doSomething(ht);

 

private String doSomething(Map pram) {

    .....

    // 比如这里需要 pram.clone(); 该怎么办呢?

    Map pram2 = pram.clone();   // 会出错的,因为Map接口中没有clone方法,那是Cloneable接口中的

}

 

 

书上说“没有理由在编写一个方法时使用Hashtable作为输入,相反,应该使用Map”。

 

但是我想问的是:一个类可能实现多个接口,如果不同接口中所定义的方法,都要用到,那么该选择哪个接口作为“代表”呢?恐怕哪个都是片面的。比如,如果我要在方法对传入的参数做clone操作,那么就必须使用Hashtable作为参数了,因为它还实现了Cloneable接口。

 

可以说这种时候,就是一个充分的理由,使用类(Hashtable)来声明了吗??

 

   发表时间:2009-05-21  
1. 这个例子不合适,Map可以使用其他方法克隆一份,例如取出所有的kye/value组装成一个新的Map

2. 思考问题的顺序有问题。不应该从具体类的角度考虑选择哪个接口作为代表,而是首先考虑使用该类的方法需要用到哪个接口,然后让那个具体类去实现该接口,如果该具体类无法变更(例如是java api的类),则自己重新封装一个。
0 请登录后投票
   发表时间:2009-05-21  
clone is not a good method

maybe you will like Collections.unmodifiedMap(pram)
0 请登录后投票
   发表时间:2009-05-22  
楼上两位,clone只是我举的一个例子。可能是这个例子不好。

按照 silentlakeside 的说法,思考顺序反了,我也是赞同的。

最先考虑的应该是我需要一个什么样的功能(接口),然后是实现它。

但,如果一开始的设计时,就知道我要使用的两个功能是不搭边的,它们怎么看也是要被两个接口定义的,这时该如何呢? 不能因为要在一个方法中使用,就把它们都定义在一个接口中呀。而且,如果很明显,API中已经有这样的接口了,它们也是分别的两个,如何呢?总不能自己在重写一个,把API中的两个接口合二为一吧。
0 请登录后投票
   发表时间:2009-05-22  
TonyLian 写道
楼上两位,clone只是我举的一个例子。可能是这个例子不好。

按照 silentlakeside 的说法,思考顺序反了,我也是赞同的。

最先考虑的应该是我需要一个什么样的功能(接口),然后是实现它。

但,如果一开始的设计时,就知道我要使用的两个功能是不搭边的,它们怎么看也是要被两个接口定义的,这时该如何呢? 不能因为要在一个方法中使用,就把它们都定义在一个接口中呀。而且,如果很明显,API中已经有这样的接口了,它们也是分别的两个,如何呢?总不能自己在重写一个,把API中的两个接口合二为一吧。

“最先考虑的应该是我需要一个什么样的功能(接口),然后是实现它。”


要多想、多分析,否则接口容易沦为一个单纯实现层面的东西,接口的产生可能就不是严肃了。

很多时候,你需要某一个东西,这个东西不存在,你可以去创造,当然,也多去想想可不可以由已有的东西转化过来。
0 请登录后投票
   发表时间:2009-05-27  
这样讲吧,你的设计不合理.
你需要使用参数对象的功能,但你的参数类型没有提供该功能(换句话说你的类没有保证被实现特定方法),合适么?必须提供具有该功能的对象才行.这里hashmap是'碰巧'实现了map接口,但是你的方法内部确实需要一个hashmap类型的对象,而不是一个map对象.这里拿jdk api来说不合适,不知道你听懂我的意思了么,大概以你的理解应该有个hashmap接口你就想通了?使用子类扩展功能的时候其实它的继承意义已经变化了.垂直起落飞机是飞机,但是用到垂直起落功能的时候,它是飞机但是更始"可以垂直起落的机器".既然方法内部更重视垂直起落这个词,那我就应该传入具有垂直起落飞机,而不是飞机.
0 请登录后投票
   发表时间:2009-05-27  
楼上讲的很明白,我一开始也有这样但稍微模糊的认识。
但是,‘碰巧’API中已经为我们设计好了“飞机”和“可垂直起降的机器”,
而我要用到对象的 垂直起飞() 方法,也要用到 驾驶员席位数 域,
也就是说,如果一个 “名为垂直起降飞机” 的类,继承了 “飞机” 这个抽象类,同时实现了“可垂直起降的机器”这么个接口,那不正合适吗。
但当作为参数传递时,显然只用“可垂直起降的机器”这个接口是不行的。

public class 鹞式战斗机 extends 飞机 implements 可垂直起降的机器

就像 public class Hashtable extends Dictionary implements Map

当然 Hashtable 还实现诸如 Cloneable 等几个接口,如我一楼的例子,
如果我的方法中需要用到 values() 方法(实现Map接口),又要用到 keys() 方法 (实现Dictionary抽象类),甚至还要用到 clone() 方法 (实现Cloneable接口)

例子已经很清楚了,按照楼上几位的说法。在设计之初就该考虑我需要一个什么样的接口,而不是什么样的实现。

那么,就如果用战斗机那个例子,很明显,你会告诉,先写一个“垂直起降飞机”或“垂直起降战斗机”这么个接口(是不是抽象类也可以呀?)

但是,如果就是 Hashtable Map Dictionary Cloneable 这个例子呢?你不会建议我(为API追加)重写一个 三合一的 新接口吧??
解决方案又是什么呢? 只能硬着头皮 用 Hashtable 做参数了吗??
0 请登录后投票
   发表时间:2009-05-27   最后修改:2009-05-27
恩,的确如楼主所说的,如果这样的话使用实现类是最恰当的。毕竟也只是说优先于类,并没有说必须是接口。事实上问题就在于接口到底是干什么的,依我的理解应该就是约束动作的。那么这样说来,跨栏运动员=人+能跨栏,问题也就变成既然人和能跨栏都有了,有必要为跨栏运动员再做一个接口?我之所以说hashmap这个例子不太好是因为haspmap没有实际的生活意义(或者说不便理解,当然也是可以说的通的),而且重要的是它已经是实现类了,它并没有再去抽象一层出来,因为我们通常说参加跨栏比赛的是跨栏运动员,而不是能跨栏的人,这样的思维最自然最oo,因为无论是人或者能跨栏接口的实现都不能代表跨栏运动员,因此设计的时候可能会做一个跨栏运动员的抽象,再细分为不同性别不同赛程的运动员:public class 110栏 implements 跨栏运动员 而不是 public 110栏 extends 人 implements 能跨栏,这里多了一层抽象就自然多了(跨栏运动员才是人和能跨栏的抽象,110栏是更具化的东西,不应该直接去继承或实现),对于参加跨栏比赛这个方法(楼主的设计只能使用具体类),这个时候传递跨栏运动员接口优于传递类才是joshua bloch 的初衷的吧。这个是我的拙见。当然对于楼主这个特定的例子,我还是表示赞同。
0 请登录后投票
论坛首页 Java企业应用版

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