面向接口编程 & 面向对象编程
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
关键字这么简单。可以理解为接口是对具体实现的抽象。试想一下,团队协同以及代码健壮可维护性的需求日益增强的趋势下,通过暴露接口来提供服务本身是一件非常愉悦的事情。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
和具体实现类之间起到了很好的过渡效果。