在Java API設計中,面向接口編程的思想,以及接口和工廠的關係

如今的java API的設計中,提倡面向接口的編程,即在API的設計中,參數的傳遞和返回建議使用接口,而不是具體的實現類,如一個方法的輸入參數類型應該使用Map接口,而不是HashMap或Hashtable等具體的實現類。這樣作的好處是,程序容易擴展。若是使用Map做爲參數,用戶可使用任何實現Map接口的類做爲參數,而不是僅僅限制使用HashMap或Hashtable做爲參數,使程序的實現更加靈活。html

  接口(Java的Interface),只定義了一些抽象的方法(也能夠定義一些常量,但不鼓勵這麼作),沒有具體的實現,這些抽象方法的具體實現,必須由實現(implements)接口的具體類來實現。接口反映了系統設計人員對系統的抽象理解。實際上,接口只是定義了一個規範和約束,要求實現類必須遵循這些規範和約束,你們編程時都要按照這個規範進行編程。java

  使用接口進行編程時,API的使用者只使用接口進行調用,而無論接口是如何實現的,這樣你就能夠隨意更換接口的實現廠商(provider)。假如,你以爲廠商的接口實現很差,能夠換一個廠商的實現類,甚至本身來實現,但確基本上不須要更改已經寫好的應用程序(由於應用程序只對接口進行調用,而全部的實現類的接口都是相同的)。mysql

  如java.sql包定義了不少jdbc的接口,你們在進行jdbc編程時都只須要使用Connection、PreparedStatment、ResultSet等接口,而不須要考慮這些接口的具體實現類是什麼。每種數據庫,如Oracle、SQLServer、DB2的JDBC驅動則是由各個廠商提供具體實現類,來實現統一的JDBC API接口規範。sql

  面向接口的編程中,工廠(Factory)的使用恐怕是最經常使用的,接口和工廠的關係是密不可分的,工廠,簡單的說,就是生產接口實現類實例的類。能夠說,在面向接口的編程中,工廠方法發揮了極其重要的做用。數據庫

  在開發應用時,如何對接口進行調用,如何實例化接口對象?你沒法經過相似於new Inteface1()等來進行實例化,由於接口是不能實例化的(接口即Java的Interface不是類,全部方法都是抽象的,因此不能實例化,可以實例化的只能是接口的實現類)。實例化接口類對象主要有兩種方法:編程

1) 直接new 接口的實現類的實例,相似於緩存

Map map=new HashMap(); //HashMap實現了Map接口oracle

Interface1 instance=new ConcreteClass1();  //ConcreteClass1實現了Inteface1接口curl

  在一個API內部,這樣寫無可厚非,由於對調用者是屏蔽的,你從此將HashMap改成hashtable,不會影響到API調用者的程序。可是對於一個API調用的程序來講,這樣就不太好了。以下面的調用(出租車公司增長一種高級轎車):ide

Car car=new BenzCar(); //BenzCar實現了Car接口

carRentCompany.addSuperCar(car);

  雖然能夠這樣,但這與面向接口的編程的原則不符,由於這要求你必需要知道接口的實現類,若是你有天想換一個實現類(如將奔馳車換成寶馬車),就麻煩了,你必須找到你之前的應用程序源代碼,將每個調用接口實現類的地方都改過來,工做量比較大了。

  還有一種更好的方法,就是使用工廠。

2) 使用工廠,如

Car car=CarFactory.getSuperCar();

carRentCompany.addSuperCar(car);

  由工廠來提供實例化方法,你沒必要關心實例化類是哪個。固然你必須知道工廠類是哪個,更換接口實現的時候,你只須要修改工廠的方法就能夠了,其他的都不須要更改了。如上面的場景,將奔馳車換成寶馬車,只要更改CarFactory.getSuperCar()方法就能夠了,用戶調用API的程序不須要修改。

  舉個jdbc調用的例子:

Oracle的jdbc調用:

    ... ...

    Class.forName("oracle.jdbc.driver.OracleDriver";);

    Connection conn=DriverManager.getConnection(jdbcurl,username,password);

SQLServer的jdbc調用:

    ... ...

    Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");

    Connection conn=DriverManager.getConnection(jdbcurl,username,password);

MySQL的jdbc調用:

    ... ...

    Class.forName("com.mysql.jdbc.Driver");

    Connection conn=DriverManager.getConnection(jdbcurl,username,password);

 

  這裏,DriverManager就是工廠,經過getConnection()方法來生產出數據庫鏈接對象Connection, 用戶使用Connect就能夠實現JDBC編程了。

  可是,DriverManager是怎麼知道使用的哪一個數據庫,使用哪一個提供商的JDBC驅動來生產Connectin的嗎?答案在這裏,緣由就在Class.forName()的過程當中,Class.forName()是將一個類初始化,這裏,調用不一樣廠商提供jdbc驅動時,使用了不一樣的jdbc驅動類的類名,該方法會初始化化該Driver類,該類在初始化時(static{}方法中)會初始化一個本身的Driver類實例,並將實例註冊到DriverManager中(的一個Vector中),再經過DriverManager中的getConnection()方法找到Driver實例(經過jdbcurl),再調用Driver實例的getConnection()方法。Driver實例也是一個生產Connection接口實例的工廠。DriverManager其實是一個保存了各個jdbc驅動的一個緩存管理類,緩存了各個驅動程序,並調用各個jdbc的驅動程序生產Connection對象。

  能夠看出,只須要更改Driver的類名,提供不一樣的jdbcUrl和用戶、密碼,就能夠生產出一個數據庫鏈接(Connection接口類的實例)。

 

  建議:若是你使用配置文件來提供工廠類的名字,程序經過調用配置文件來讀取工廠的類名,更換接口實現就更簡單了,你只須要改配置文件就能夠了,而不須要更改程序。

接口和工廠之間關係形象比喻:

  接口就比如是產品規格,如螺母和螺釘的產品規格,規定了不一樣的大小尺寸,左旋等,工廠比如生產這些螺母和螺釘的加工企業,而接口的實例比如不一樣工廠生成出的螺母、螺釘的產品。每個不一樣的工廠雖然生成出的不一樣螺母和螺釘產品,但都必須遵照這個產品規格,這樣不一樣工廠生產出來的不一樣的螺母和螺釘才能夠擰在一塊兒使用,你也能夠隨意更換不一樣工廠生產出來的螺母或螺釘,而不會出現問題。

http://blog.sina.com.cn/s/blog_6f505d710100mxsy.html

相關文章
相關標籤/搜索