`
TonyLian
  • 浏览: 396770 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

优先使用接口而不是类

阅读更多

正在研读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)来声明了吗??

 

分享到:
评论
7 楼 TheMarine 2009-05-27  
恩,的确如楼主所说的,如果这样的话使用实现类是最恰当的。毕竟也只是说优先于类,并没有说必须是接口。事实上问题就在于接口到底是干什么的,依我的理解应该就是约束动作的。那么这样说来,跨栏运动员=人+能跨栏,问题也就变成既然人和能跨栏都有了,有必要为跨栏运动员再做一个接口?我之所以说hashmap这个例子不太好是因为haspmap没有实际的生活意义(或者说不便理解,当然也是可以说的通的),而且重要的是它已经是实现类了,它并没有再去抽象一层出来,因为我们通常说参加跨栏比赛的是跨栏运动员,而不是能跨栏的人,这样的思维最自然最oo,因为无论是人或者能跨栏接口的实现都不能代表跨栏运动员,因此设计的时候可能会做一个跨栏运动员的抽象,再细分为不同性别不同赛程的运动员:public class 110栏 implements 跨栏运动员 而不是 public 110栏 extends 人 implements 能跨栏,这里多了一层抽象就自然多了(跨栏运动员才是人和能跨栏的抽象,110栏是更具化的东西,不应该直接去继承或实现),对于参加跨栏比赛这个方法(楼主的设计只能使用具体类),这个时候传递跨栏运动员接口优于传递类才是joshua bloch 的初衷的吧。这个是我的拙见。当然对于楼主这个特定的例子,我还是表示赞同。
6 楼 TonyLian 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 做参数了吗??
5 楼 TheMarine 2009-05-27  
这样讲吧,你的设计不合理.
你需要使用参数对象的功能,但你的参数类型没有提供该功能(换句话说你的类没有保证被实现特定方法),合适么?必须提供具有该功能的对象才行.这里hashmap是'碰巧'实现了map接口,但是你的方法内部确实需要一个hashmap类型的对象,而不是一个map对象.这里拿jdk api来说不合适,不知道你听懂我的意思了么,大概以你的理解应该有个hashmap接口你就想通了?使用子类扩展功能的时候其实它的继承意义已经变化了.垂直起落飞机是飞机,但是用到垂直起落功能的时候,它是飞机但是更始"可以垂直起落的机器".既然方法内部更重视垂直起落这个词,那我就应该传入具有垂直起落飞机,而不是飞机.
4 楼 zhuxing 2009-05-22  
TonyLian 写道
楼上两位,clone只是我举的一个例子。可能是这个例子不好。

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

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

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

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


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

很多时候,你需要某一个东西,这个东西不存在,你可以去创造,当然,也多去想想可不可以由已有的东西转化过来。
3 楼 TonyLian 2009-05-22  
楼上两位,clone只是我举的一个例子。可能是这个例子不好。

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

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

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

maybe you will like Collections.unmodifiedMap(pram)
1 楼 silentlakeside 2009-05-21  
1. 这个例子不合适,Map可以使用其他方法克隆一份,例如取出所有的kye/value组装成一个新的Map

2. 思考问题的顺序有问题。不应该从具体类的角度考虑选择哪个接口作为代表,而是首先考虑使用该类的方法需要用到哪个接口,然后让那个具体类去实现该接口,如果该具体类无法变更(例如是java api的类),则自己重新封装一个。

相关推荐

    Java开发常见问题总结.docx

    优先考虑接口而不是实现,利用多态性。 适当使用设计模式提升代码复用和可维护性。 集合与数据结构: 根据需求选择合适的集合类型(List, Set, Map等)。 对于并发环境,使用线程安全的集合类如ConcurrentHashMap、...

    【05-面向对象(下)】

    •一个类可以实现一个或多个接口,继承使用extends关键字,实现接口则使用implements关键字。 实现接口 •一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是...

    Qt class designing rule(Qt类设计规范)

    Qt 类设计原则,内容不多,待续 – 面向接口编程而不是实现 (Code to an interface rather than to an implementation.) – 优先使用组合而非继承 (Favor Composition Over Inheritance)

    design-patterns:NET Core的C#优先设计模式实现

    优先考虑组成而不是继承。 编程到接口,而不是实现。 努力实现交互对象之间的松耦合设计 类应该为扩展而开放,但为修改而封闭。 取决于抽象。 不要依赖具体的类。 最少知识的原则:仅与您的直属朋友交谈。 ...

    java设计模式导论

    设计模式实用思想,设计模式的三个重要原则 一,针对接口编程,而不是针对实现编程 二,优先使用对象组合,而不是类继承 三,封装变化点

    雕刻机5轴步进电机驱动器原理图+使用说明(带手控接口)

    3、带手控接口,可以使用手控对步进电机进行控制 4、带四路限位开关接口,可对实现限位功能,设备运转安全保证。 5、带继电器控制,可控制雕刻机主轴电机。 插拔接头和驱动器的连接图 1、步进电机的基本参数: ...

    C++编程规范101条规则、准则与最佳实践PDF.rar

    第36条 优先提供抽象接口 62 第37条 公用继承即可替换性。继承,不是为了重用,而是为了被重用 64 第38条 实施安全的覆盖 66 第39条 考虑将虚拟函数声明为非公用的,将公用函数声明为非虚拟的 68

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    基本信息 作者: 臧萌 ...12.2.4 使用接口仅需一步——实现接口 342 12.2.5 接口——让类集多重类型于一身 344 12.2.6 简化recordTransport()方法 347 12.3 再探接口 349 12.3.1 重温上节中的程序 349...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    基本信息 作者: 臧萌 ...12.2.4 使用接口仅需一步——实现接口 342 12.2.5 接口——让类集多重类型于一身 344 12.2.6 简化recordTransport()方法 347 12.3 再探接口 349 12.3.1 重温上节中的程序 349...

    习----题-Java-Web程序设计教程-[共2页].pdf

    另外,在前面的比较接口中也可以使用泛型,例如例 3.3 的 MyCmp 类还可以这样来实现, 请看如下语句。 public class MyCmp implements Comparator<Student>{ public int compare(Student s1, Student s2){ …… } }...

    head-first-design-patterns:与“ Head First设计模式”书有关的源代码。 在基于.NET的解决方案中实现了本书中的一些设计模式示例

    优先考虑组成而不是继承。 力争在相互作用的对象之间实现松散耦合的设计。 最少知识的原则:仅与您的直属朋友交谈。 好莱坞原则:请勿致电给我们,我们会致电给您。 坚硬的小号英格尔-责任:一类应该有一个和唯一...

    大智慧股票本地数据读取接口(含源码)

    使用说明: 1)调用格式:FxjData2FinData(Market,DataType,FinDataLib) 其中, Market:市场代码,SH为沪市,SZ为深市,BK为板块指数,如果有其它市场数据,可有其它市场代码如HK等. DataType:数据类型,dm,cq,cw0,hq0,hq,等等...

    GO语言学习文档,适合初级入门学习

    GO是一个以通用系统语言为设计目标的系统级语言, 如 C++. 以下是针对C++程序员的一些学习拉摘要. 这文章主要讨论GO和C++的不同。 对于更一般的介绍,请另参... * Go 使用nil而不是C++中的NULL或0作为逻辑非。

    cl-webkit:对Common Lisp的WebKitGTK +的绑定

    API概述cl-webkit API紧随WebKit2 API,不同之处在于,在同时提供基于类的接口而不是功能接口的情况下,它们优先于功能接口。 也就是说*_{new,get,set}排除*_{new,get,set}方法,以使用make-instance和插槽访问器。 ...

    JavaNote:java es番石榴jdk jdk8 jsonLombokmd线程jvm spring mvc vertx设计模式风暴

    - 优先使用对象组合而不是继承。 创建型模式 工厂模式(Factory Pattern) 抽象工厂模式(Abstract Factory Pattern) 单例模式(Singleton Pattern) 建造者模式(Builder Pattern) 原型模式(Prototype Pattern)...

    TCP拦截和网络地址转换

    但本例中公司不是使用一个简单的 We b服务 器,而是使用一组 We b服务器,其 I P地址从1 9 8 . 5 0 . 1 . 1到1 9 8 . 5 0 . 5 0 . 1 0 0。在本网段中不再使用 其他的I P地址。我们希望使用 T C P拦截来保护所有...

    HeadsUpDesignPatterns:抬头设计模式

    抬头设计模式抬头设计模式书练习。SymUDuck策略模式定义一系列算法,... 优先考虑组成而不是继承。 编程到接口,而不是实现。 力争在相互作用的对象之间实现松散耦合的设计。 类应该开放以进行扩展,但封闭以进行修改

    规范:否ORM(NORM)是一个Java库,用于通过Java安全机制以更加面向SQL的方式使用数据库

    指导原则: SQL查询是以静态方式指定的,其中没有用户数据可以污染它们(即Java批注) 使用具有命名字段和类型字段的Java类(而不是冗长且易于出错的反射接口)将参数和结果(未)编组在一起优先选择编译时间,然后...

Global site tag (gtag.js) - Google Analytics