面向接口編程
-
概念:接口是一種特殊的抽象類,與一般抽象類相比,接口中的所有方法都是抽象方法,所有屬性都是常量。
-
接口通常用來定義實現類的外觀,也就是實現類的行爲定義,用來約束實現類的行爲
-
接口的思想:封裝隔離。隔離外部調用與內部實現,外部調用只能通過接口調用,不知道內部具體實現
-
接口還是抽象類:
-
優先使用接口
-
在既要定義子類的行爲,又要爲子類提供公共的功能時應選擇抽象類
-
/** *@Function: 接口(通用的、抽象的、非具體的功能) *@Author: hxq *@Date: 2014-6-18 */ public interface Api { public void operation(String s); } /** *@Function: 對接口的實現 */ public class Impl implements Api{ @Override public void operation(String s) { System.out.println(s); } } /** *@Function: 客戶端:未使用模式 */ public class Client { public static void main(String[] args) { /** * 接口的思想是封裝隔離,實現類Impl應該是被接口Api封裝並同客戶端隔離的 * 客戶端不應該知道具體的實現類是Impl */ Api api=new Impl(); api.operation("沒有模式"); } }
把這個問題描述一下:java編程中,只知道接口而不知實現,怎麼辦?一個合理的解決方案就是簡單工廠
簡單工廠(靜態工廠方法模式)
定義:
提供一個創建對象實例的功能,而無須關心其具體實現。被創建實例的類型可以是接口、抽象類,也可以是具體類
結構:
-
工廠類:工廠,選擇合適的實現類來創建Api接口對象
-
抽象產品:定義客戶需要的功能接口(Api)
-
具體產品:Api的具體實現類
/** *@Function: 簡單工廠 */ public class Factory { public static Api createApi(){ return new Impl(); } } /** *@Function: 客戶端:簡單工廠 */ public class Client { public static void main(String[] args) { Api api=Factory.createApi(); api.operation("簡單工廠 ^_^ "); } }
可配置簡單工廠
在現在的實現中,再新增一種實現,該怎麼辦呢?那就需要修改工廠類,把新的實現添加到現有系統中。類似下面這樣:
public class Factory { public static Api createApi(int type){ Api api=null; if(type==1){ api=new Impl(); }else{ api=new Impl2(); } return api; } }
如果每增加一個實現類都來修改工廠類的實現,肯定不是一個好的實現方式。對此,一種解決方式就是使用配置文件(通常是xml,也可以properties文件)。當有了新的實現類,只要在配置文件中配置即可。在簡單工廠的方法中可以使用反射,也可以使用IOC/DI(控制反轉/依賴注入)來實現。
簡單工廠的優缺點:
-
優點
- 幫助封裝:實現了組件的封裝,讓組件的外部能真正的面向接口編程
- 解耦:實現客戶端與具體實現類的解耦
-
缺點
-
可能增加客戶端的複雜度:如果通過客戶端參數來選擇實現類,就必須讓客戶端理解各個參數代表的具體功能與含義,增加使用難度,也暴露部分實現
-
不方便擴展子工廠:私有化簡單工廠構造方法,使用靜態方法創建接口,就不能通過寫簡單工廠類的子類來改變創建接口的方法的行爲。當然通常也不需要這麼做
-
簡單工廠的本質
簡單工廠的本質是:選擇實現
注意簡單工廠的重點在選擇,實現是已經做好了的。就算實現再簡單,也要由具體的實現類來實現,而不是在簡單工廠裏面實現。簡單工廠的目的在於爲客戶端選擇相應的實現,從而使得客戶端與實現解耦。這樣一來,具體實現發生了變化,就不用變動客戶端了,這個變化會被簡單工廠吸收和屏蔽掉。
簡單工廠的本質是選擇實現,所以它可以跟其他任何能具體創建對象實例的模式配合使用,比如:單例模式、原型模式、生成器模式等