abstract class和interface是java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,两者之间还是有很大区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。我认为正确运用好抽象类和接口,可以优化软件结构的设计,对软件的扩展、维护带来很大的便利。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。 2 k. D5 K0 s# t* B) o: f $ \! {; Q f6 f9 d k首先来理解一下抽象类。在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如我们xpads 项目中的交易类就可以理解为一个抽象类,即期交易、远期交易、掉期交易等都是继承交易类的具体类。即期交易、远期交易、掉期交易这些具体概念是实际存在的,而交易这个概念在问题领域中是不存在的,可以理解为一个抽象概念。正是因为抽象概念在实际问题领域中没有东西与它对应,所以用以表征抽象概念的抽象类是不能被实例化的。* A, M3 t5 P* N. q! E1 l
6 r9 b( } K1 l& ^7 {. @5 P* K9 j接下来理解一下接口,接口是面向对象设计中的一组规范,是一组方法的集合体(也可以定义一些常量),在一些软件设计模式中提倡的面向接口编程,其实就是屏蔽实现类的内部处理,增强模块的安全性、灵活性,达到软件设计的高内聚、松耦合。 . z) T" M x6 T- d8 a ) `3 p+ k j. A! B7 g. v0 U( o下面从三个方面进行比较: / z a) {7 k/ ?3 I P# R; [( Z1 ]( U( d) r
一、从语法定义层面看abstract class和interface 9 ?6 r3 E. m5 y# G
. j5 a. ~; q9 [9 M) c" ^使用abstract class的方式定义Deal抽象类的方式如下:; L6 m A- Z5 ]% o% d! g
7 c, ?( h4 N- V- ^/ zabstract class FxDeal { . V% B$ P; n4 U' t; h! w, k8 G+ [& `8 {9 h
private long dealsId; //交易流水号 # l; }4 s2 y9 [/ `" n8 ~* T* h0 t
private long blockNumber;//套流水号6 d3 s9 H" B& j5 G7 m
4 f# t- Y& R g k+ U" ]private String appls;//产品类别* t! e$ M% K' w1 C& X B
6 E- \3 P7 q& P. |
private String inputChannel;//录入渠道 ' b. v5 _. W& B3 }% F4 E) L6 y$ W9 o1 t' U
private String typeOfDeal;//交易类型 0 ~4 v- v; J" v: G s m. |8 x3 t- R& ]) Iprivate String flagOfDeal;// 特殊交易标识 0 Y; Q3 n9 l$ H2 z3 a * m1 {* ^3 W; Y {8 cprivate String bankId;//业务发生行- Q6 A) w( B" r( A6 b. s
; r! s$ G6 s! T8 v1 s. Uprivate String customerId; //客户号( H; o4 o6 H- R; e1 x
0 Z0 ?8 [/ y7 N) S/ j/ J
private String customerName;//客户名称& |/ C9 l- n# \, c' j
# d4 ^" H g) a( I: g/ p
private int customerType;//客户类型 % A# F$ ^) L/ m9 `+ p3 y9 Y `1 [! r! ?* x
private double amount1; + P$ D; u" M" g: S$ e/ [. q% k4 ]- m" ~
private double amount2; 4 U- }* t+ w7 M! I% W, D6 U3 H : r( f1 f' |: K9 | M2 P* A abstract void method1();% C8 C% C% Q: F: w
- b n+ Z/ d+ M
abstract void method2(); 0 y& u g2 `- J" L0 D9 Q/ \
" `$ R. p( h# `& _( Q& e8 t8 Z
… 6 G# F) z1 o8 e/ q( u# L+ r1 \0 g# k' Q" z* ]
}- K" @7 A, v2 x# n8 y( p" T) I+ T4 [
; L& B3 s* o* e; b4 n% @7 Q6 \* L使用interface的方式定义Deal抽象类的方式如下: $ ^" g z# R9 Q) l5 e+ T interface FxDeal { 8 w( X+ m0 o* D" C, z void method1(); $ Y. o, t, h9 x$ Q0 D void method2(); ( v, @' p$ t. D … , S, J8 C2 T. P! D# L8 R3 C } 4 ?$ o$ `% D) R) s9 z + U! L6 U a& x7 f在abstract class方式中,Deal可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface方式的实现中,Deal只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。; Y- U4 s& Y4 _
. |8 |3 L3 I& O' y6 Z8 K* l二、从编程层面看abstract class和interface' p k% C* A2 z3 ?1 m2 \& C: m
) x- m# P) D' Q# p6 v+ Y首先,abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。 2 V7 d8 U2 k0 t0 R2 n 4 I4 [$ d+ A5 V( w2 B" a' ^其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会增加一些复杂性,有时会造成很大的麻烦。( S' M0 G' O' |3 @