使用工廠模式與泛型對三層架構的每一層進行解耦


  我們都知道在web開發時經常使用三層架構(web、service、dao),每一層有着自己的實現類,而通過對實現類進行抽取方法形成接口,每一層通過接口進行上下層之間的耦合。例如在業務service層和數據訪問dao層之間,當dao層寫好了對數據庫的增刪改查方法時,抽取成dao接口,而在service如果要調用dao層的方法就只要使用dao接口即可,但是關鍵是在service層使用dao接口的時候,如何獲取dao接口的實現對象是個問題。

 

  案例:在數據訪問dao層,編寫好了一個對數據庫中表user的增刪查改方法,封裝於UserDaoImpl實現類中,將UserDaoImpl實現類中的方法抽取出來成UserDao接口,那么如果在service中要使用User對象,那么就必須要使用到dao層中有關User的操作,由多態的靈活性,在service層中只要使用UserDao接口即可,但是光有一個接口引用對象沒有用,我們必須要有UserDaoImpl這樣的真正的實現類才能構建(new)出對象,難道要在service層使用UserDao dao = new UserDaoImpl();這樣的代碼?這樣明顯使dao層的實現類侵入了service層中,如果將來我們的實現類從UserDaoImpl變成了UserDaoJdbcImpl或者UserDaoXmlImpl這樣的豈不是要在service層的代碼中改動?

  

  如何對不同層的代碼進行解耦,關乎整個應用的靈活性,下面我們就來使用工廠模式來結局這個問題。

  創建一個工程,為了簡潔說明上面的例子,我們就創建四個類或接口就好了,結構如下圖所示:

  

  在com.fjdingsd.daoimpl包中的dao層的實現類,這里面封裝了一個對User對象的增刪改查的具體實現方法(方法內容略):

 1 package com.fjdingsd.daoimpl;  2 public class UserDaoImpl implements UserDao {  3  @Override  4     public void insert(){  5         。。。//添加User對象
 6  }  7     
 8  @Override  9     public void delete() { 10         。。。//刪除User對象
11  } 12     
13  @Override 14     public void update() { 15         。。。//修改User對象
16  } 17     
18  @Override 19     public void find() { 20         。。。//查找User對象
21  } 22 }
View Code

  將該dao對User的實現類方法抽取到UserDao接口中去:

1 package com.fjdingsd.dao; 2 public interface UserDao { 3     public abstract void insert(); 4     public abstract void delete(); 5     public abstract void update(); 6     public abstract void find(); 7 }
View Code

  如果沒有使用工廠模式,那么因為沒什么好的方法,所以只能在service層的實現類中直接使用UserDaoImpl來構建對象,但是我們這里使用工廠模式,來避免這個問題。使用工廠模式為了便於靈活性,我們將dao層接口和dao層的實現類在配置文件factory.properties中定義,以dao接口名作為關鍵字,以dao實現類的全名(包名+類名)作為關鍵字的值。以dao層中對User對象為例,在factory.properties中定義如下:

    UserDao=com.fjdingsd.dao.impl.UserDaoImpl

  使用這樣配置的好處在於以后對於UserDao接口,如果我們想更換實現類,只要改動配置文件即可,代碼中完全不需要修改。

  在工廠類DaoFactory中的代碼如下:

 1 package com.fjdingsd.factory;  2 public class DaoFactory {  3     
 4     private static DaoFactory instance = new DaoFactory();  5     private Properties config = new Properties();  6     
 7     private DaoFactory(){  8         InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("factory.properties");    //讀取配置文件裝載進輸入流
 9         try { 10             config.load(in); //將配置文件封裝進Properties對象中
11             
12         } catch (IOException e) { 13  e.printStackTrace(); 14  } 15  } 16     
17     public static DaoFactory getInstance() { 18         return instance; 19  } 20     
21     public <T> T createDao(Class<T> clazz) { 22         String interfaceName = clazz.getSimpleName();//獲取配置文件中的接口關鍵字
23         String className = config.getProperty(interfaceName); //根據接口名獲取配置文件中的具體實現類完整名稱
24         try { 25             T bean = (T) Class.forName(className).newInstance();//使用反射創建實現類的一個實例對象
26             return bean; 27         } catch (Exception e) { 28             throw new RuntimeException(e); 29  } 30  } 31 }
View Code

  這樣在service層的實現類中以dao層接口引用具體dao層的實現類就不需要直接創建對象,直接使用工廠模式加泛型即可,如下代碼所示:

1 package com.fjdingsd.service.impl; 2 public class BussinessServiceImpl { 3     
4     //UserDao uDao = new UserDaoImpl(); 以前未使用工廠模式加泛型之前的寫法
5     UserDao uDao = DaoFactory.getInstance().createDao(UserDao.class); 6     。。。//其他代碼,此處略
7 }
View Code

分析:

  工廠模式負責一部分接口對象的實現類生成,建議使用單例模式,上面的示例也是這樣。工廠模式使用單例的好處在於如果要修改代碼,那么只要找工程即可,如果每一個接口的實現類都配一個工廠,那么工廠會太多,不利於程序的簡潔。

  在工廠中,為某個接口創建實現類對象,我們使用 配置文件+泛型 的方法,配置文件前面已經說過了,如果想更換某個接口的實現類只要修改配置文件即可。而使用泛型,可以很優雅地避免對某個具體的接口都要寫一個方法來創建對象,如上例在工廠中的createDao方法,只要根據配置文件信息就可以為接口獲取一個對應的實現類,同時要注意在配置文件中的關鍵字和值一定要是和已經定義好的接口名和類名匹配。請好好品嘗消化上面的例子。

 

 

 

          


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM