面向接口編程 & 面向對象編程
Interface-based programming, also known as interface-based architecture, is an architectural pattern for implementing modular programming at the component level in an object-oriented programming language which does not have a module system. (面向接口編程,也被熟知為基于接口的設計,是一種基于組件級別的,面向對象語言的模塊化編程設計實現)
面向接口編程和面向對象編程實際上是兩個不同層級的概念。理論上說具有對象概念的程序設計都可以稱之為面向對象編程,而面向接口編程則是從組件的級別來設計代碼,人為地將抽象與實現分離。面向接口編程僅僅只是面向對象編程的一種模塊化實現形式而已。
所謂“接口”
面向接口編程中的"接口"二字具體到語言中(Java)不僅僅是interface
關鍵字這么簡單??梢岳斫鉃榻涌谑菍唧w實現的抽象。試想一下,團隊協同以及代碼健壯可維護性的需求日益增強的趨勢下,通過暴露接口來提供服務本身是一件非常愉悅的事情。A需要調用B中的服務,A卻不需要去仔細閱讀B寫的代碼,通過接口文檔就可以看出對應業務的方法和參數類型,進而使用RMI或者RPC等相關技術實現模塊化調用。而這一切本身就是面向接口編程。
abstract class 和 interface
為什么有這樣的問題呢?很多剛接觸面向接口編程的Java開發者都或多或少遇到這樣的困惑。他們大多會認為,既然是面向接口編程,那么把實現抽象為接口就是優良的設計。但實際上他們混淆了Java中的interface
和面向接口編程中的“接口”概念。實際上,interface
、abstract class
以及普通的class
都能成為所謂的接口,甚至abstract class
的功能可以更加強大。那么問題來了,interface
和abstract class
分別對應于什么場景下使用更合適一些?
interface
和abstract class
區別在于interface
約定的是務必要實現的方法和參數,強調規則的制定;abstract class
則在抽象的同時允許提供一些默認的行為,以達到代碼復用的效果。例如定義一些基礎、初始化以及類回收方法等。另外,還有一個常識性的區別,一個實現類(相對于抽象而言)可以實現多個interface
,而只能繼承一個abstract class
,在代碼設計的過程中務必注意。
策略模式 (Strategy Pattern)
作為面向接口編程的一個典型設計模式,應用相當普遍。本文之所以討論策略模式,是該模式本身把“面向接口編程”思想很好地體現了。這里舉個簡單的例子以供參考。
//定義策略接口
interface Strategy { public void solve(); }
/************** 策略一 **************/
//策略1抽象類
abstract class TemplateMethod1 implements Strategy {
public void solve() {
start();
while (nextTry() && ! isSolution())
;
stop();
}
protected abstract void start();
protected abstract boolean nextTry();
protected abstract boolean isSolution();
protected abstract void stop();
}
//策略1實現類
class Impl1 extends TemplateMethod1 {
private int state = 1;
protected void start() {
System.out.print( "start " );
}
protected void stop() {
System.out.println( "stop" );
}
protected boolean nextTry() {
System.out.print( "nextTry-" + state++ + " " );
return true;
}
protected boolean isSolution() {
System.out.print( "isSolution-" + (state == 3) + " " );
return (state == 3);
}
}
/************** 策略二 **************/
//策略2抽象類
abstract class TemplateMethod2 implements Strategy {
public void solve() {
while (true) {
preProcess();
if (search()) break;
postProcess();
}
}
protected abstract void preProcess();
protected abstract boolean search();
protected abstract void postProcess();
}
//策略2實現類
class Impl2 extends TemplateMethod2 {
private int state = 1;
protected void preProcess() { System.out.print( "preProcess " ); }
protected void postProcess() { System.out.print( "postProcess " ); }
protected boolean search() {
System.out.print( "search-" + state++ + " " );
return state == 3 ? true : false;
}
}
/************** 測試類 **************/
public class StrategyDemo {
public static void clientCode( Strategy strat ) {
strat.solve();
}
public static void main( String[] args ) {
Strategy[] algorithms = { new Impl1(), new Impl2() };
for (int i=0; i < algorithms.length; i++) {
clientCode( algorithms[i] );
}
}
}
其中interface
定義的是最抽象的東西,也就是上文說的規則,但是過度抽象不利于代碼的復用。于是abstract class
的優勢就能很好的利用了。介于絕對抽象和具體實現之間,abstract class
既能夠實現接口方法,提供一個默認方法支持(所謂“策略”),又能制定出該策略下附帶的某些必須實現的抽象方法(所謂“規則”),在interface
和具體實現類之間起到了很好的過渡效果。