1.不用模式的解決方案
1.1 示例
(1)首先定義接口Api,示例代碼如下:
public interface Api {
public void test1(String s);
}
(2)有了Api,自然要有實作,此處功能為輸出字元串,示例如下:
public class ImplA implements Api{
@Override
public void test1(String s) {
System.out.println("Now In Impl. The input s == " + s);
}
}
(3)用戶端調用實作
public class Client {
public static void main(String[] args){
Api api = new ImplA();
api.test1("哈哈,不要緊張,隻是一個測試而已!");
}
}
1.2 分析問題
可以看到上例中,用戶端已經知道了相應的實作,是以根本沒有做到“封裝隔離”。
要做到“封裝隔離”,用戶端就不應該知道具體的實作是什麼,那麼“new Impl()”就應該封裝起來,讓用戶端看不到。
2.帶模式的解決方案
2.1 簡單工廠重寫示例
(1)Api與相應實作Impl都與上面相同
此處主要說一下簡單工廠Factory,示例如下:
public class Factory {
//傳回的執行個體包裹在Factory中,這樣用戶端就看不到了
public static Api create(){
return new ImplA();
}
}
(2)重寫用戶端代碼,代碼如下:
public class Client {
public static void main(String[] args){
//這個時候就不用顯式寫出new Impl(),而是通過工廠來傳回
Api api = Factory.create();
api.test1("正在測試重寫簡單工廠。。。");
}
}
從用戶端來看,不需要知道具體的實作是什麼,也不需要知道如何實作的,隻知道從工廠獲得了一個接口對象,然後通過接口來擷取想要的功能。
2.2 帶選擇的簡單工廠
上面重寫示例中,隻有一種實作,要是有多種實作又該如何呢?
(1)Api和相應實作不變
在上面的基礎上再添加一種實作ImplB,代碼如下:
public class ImplB implements Api {
@Override
public void operation(String s) {
System.out.println("ImplB s == "+ s);
}
}
(2)修改簡單工廠Factory,做到選擇實作,代碼如下:
public class Factory {
public static Api create(int condition){
Api api = null;
if(condition == 1){
api = new ImplA();
}else if(condition == 2){
api = new ImplB();
}
return api;
}
}
(3)修改用戶端代碼:
public class Client {
public static void main(String[] args){
//用戶端通過1或者2,來選擇相應的實作
Api api = Factory.create(1);
api.operation("正在使用簡單工廠");
}
}
2.3 帶選擇的簡單工廠的缺陷
帶選擇的簡單工廠有很大的局限性,如果有多重選擇,那麼就要在工廠中多次判斷,複雜性大大提升。另外從用戶端調用工廠的時候傳入選擇的參數,增加了寫死。
這種複雜性不能放在代碼中來判斷,而應該放在外部,從代碼中獨立出來,放在配置中。
2.4 可配置的簡單工廠
(1)配置檔案用properties檔案,定義一個“FactoryTest.properties”檔案放在工廠類的同一個包下,内容如下:
ImplClass=com.zte.rewriteonproperties.ImplA
(2)修改工廠類Factory,代碼如下:
public class Factory {
public static Api createApi(){
Properties p = new Properties();
InputStream in = null;
//讀取配置檔案
in = Factory.class.getResourceAsStream("FactoryTest.properties");
try {
p.load(in);
} catch (IOException e) {
System.out.println("裝載工廠配置檔案出錯了,具體的堆棧資訊如下:");
e.printStackTrace();
}finally {
try {
//讀取完畢,要記住關流
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Api api = null;
try {
try {
//反射建立執行個體
api =(Api)Class.forName(p.getProperty("ImplClass")).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return api;
}
}
(3)用戶端代碼示例如下:
public class Client {
public static void main(String[] args){
//可以看到,此時就不需要傳入參數,複雜性直接轉移到配置檔案中控制
Api api = Factory.createApi();
api.test1("哈哈哈,不要緊張,測試而已!");
}
}
3.思考簡單工廠
本人還處于學習階段,在使用簡單工廠方面還缺少經驗。
根據我的了解,在同一個功能有多重實作的時候,就可以選用簡單工廠,一方面能夠做到接口隔離,另一方面能夠做到選擇實作,集中管理和控制。
舉個例子,同樣的列印功能,可以用愛普生的,或者惠普的。這些列印廠家都實作了列印标準,同一接口。
(1)首先有個同一的接口Print
public interface Print{
public void print(String s);
}
(2)然後再有多個實作EpsonImpl,HpImpl
public class EpsonImpl implements Print{
public void print(String s){
System.out.println("this is EpsonPrinter");
}
}
public class HpImpl implements Print{
public void print(String s){
System.out.println("this is EpsonPrinter");
}
}
再之後就可以從多個實作中做出選擇,完成列印功能的隔離。