package com.ithema.jdbc; import java.sql.*; /** * 程序耦合 */ public class JdbcDemo1 { public static void main(String[] args) { try { DriverManager.registerDriver(new com.mysql.jdbc.Driver()); Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/fresh","root","root"); PreparedStatement pstm=conn.prepareStatement("select * from usertable"); ResultSet rs=pstm.executeQuery(); while (rs.next()){ System.out.println(rs.getString("username")); } rs.close(); pstm.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
下面是pom裏面的依賴包文件的引入java
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies>
當程序正常運行,能夠看到是有查詢到數據輸出mysql
可是當咱們把jdbc的依賴包註銷掉sql
<!--<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies>-->
程序還會正常查詢語句嘛,顯示結果以下數據庫
在程序編譯的初期就顯示,這個依賴類不存在,那程序就不能運行,這個就是咱們說的耦合!!簡單點來講就是程序之間的依賴關係架構
耦合主要分爲兩種:類之間的依賴、方法之間的依賴ide
解耦的含義就是下降程序之間的依賴關係,因此咱們在實際開發中要作到編譯期不依賴,運行期才依賴函數
如何解決這個依賴問題?類之間的依賴關係測試
一、在建立對象的時候,使用反射來建立對象,避免使用new關鍵ui
劃線部分就是使用了反射註冊驅動,裏面的內容只是字符串,不是一個類,可是裏面字符串是一個mysql數據庫,當之後要換數據庫的時候仍是要改驅動spa
二、經過讀取配置文件來獲取建立對象全限定類名
三層架構咱們前面都學過,層與層之間都是相互依賴的關係,ui(視圖層)調用service裏面的實現方法,service調用dao層持久層裏面的方法實現數據的查詢,這就使得相互之間的依賴關係很強,缺乏那一個實現方法,程序都不能正常實現,那有什麼好的解決方法沒???
解決方法1、建立一個BeanFactory,用工廠模式解耦
實現思路
一、須要一個文件來配置咱們的service和dao,配置的內容爲:惟一標識=全限定類名(keyvalue)
二、經過讀取配置文件中配置的內容來反射建立對象
package com.ithema.jdbc.factory; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; /** * 一個Bean對象的工廠 * Bean在計算機英語中,有可重用組件的含義 * JavaBean:用Java語言編寫的可重用組件 * JavaBean>實體類 * 做用它就是建立咱們使用service和dao對象的 * * 實現方法: * 一、須要一個文件來配置咱們的service和dao * 配置內容:惟一標識=全限定類名(keyvalue) * 二、經過讀取配置文件中配置的內容,反射對象 * * 配置文件能夠是properties或者是xml */ public class Beanfactory { //定義一個properties對象 private static Properties props; //使用靜態代碼塊建立Properites對象 static { try { //實例化對象 props=new Properties(); //獲取properites流對象 InputStream in=Beanfactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); }catch (Exception e){ throw new ExceptionInInitializerError("初始化properties失敗"); } } /** * 根據bean的名稱獲取bean對象 * @param beanName * @return */ public static Object getBean(String beanName) { Object bean=null; try { String beanPath = props.getProperty(beanName); bean = Class.forName(beanPath).newInstance();//經過反射來建立對象 } catch (Exception e) { e.printStackTrace(); } return bean; } }
properites配置文件內容
#全限定類名 accountService=com.ithema.jdbc.service.impl.AccountServiceImpl accountDao=com.ithema.jdbc.dao.impl.AccountDaoImpl
package com.ithema.jdbc.service; /** * 帳戶業務層的接口 */ public interface IAccountService { /** * 模擬保存帳戶 */ void saveAccount(); }
package com.ithema.jdbc.service.impl; import com.ithema.jdbc.dao.IAccountDao; import com.ithema.jdbc.dao.impl.AccountDaoImpl; import com.ithema.jdbc.factory.Beanfactory; import com.ithema.jdbc.service.IAccountService; /** * 帳戶的業務層實現類 */ public class AccountServiceImpl implements IAccountService { //private IAccountDao accountDao=new AccountDaoImpl(); private IAccountDao accountDao= (IAccountDao) Beanfactory.getBean("accountDao"); public void saveAccount(){ accountDao.saveAccount(); }; }
package com.ithema.jdbc.dao; /** * 帳戶的持久層接口 */ public interface IAccountDao { void saveAccount(); }
package com.ithema.jdbc.dao.impl; import com.ithema.jdbc.dao.IAccountDao; /** * 帳戶持久層實現類 */ public class AccountDaoImpl implements IAccountDao { @Override public void saveAccount() { System.out.println("保存了帳戶!!"); } }
測試類實現代碼,測試結果以下
package com.ithema.jdbc.ui; import com.ithema.jdbc.factory.Beanfactory; import com.ithema.jdbc.service.IAccountService; import com.ithema.jdbc.service.impl.AccountServiceImpl; /** * 模擬一個表現層,用於調用業務層 */ public class Client { public static void main(String[] args) { //IAccountService as=new AccountServiceImpl(); IAccountService as=(IAccountService) Beanfactory.getBean("accountService"); as.saveAccount(); } }
可是用工廠模式解耦依然存在問題,當在test屢次建立對象時候結果以下
package com.ithema.jdbc.ui; import com.ithema.jdbc.factory.Beanfactory; import com.ithema.jdbc.service.IAccountService; import com.ithema.jdbc.service.impl.AccountServiceImpl; /** * 模擬一個表現層,用於調用業務層 */ public class Client { public static void main(String[] args) { //IAccountService as=new AccountServiceImpl(); for (int i=0;i<5;i++){ IAccountService as=(IAccountService) Beanfactory.getBean("accountService"); System.out.println(as); } //as.saveAccount(); } }
每次調用構造函數都會建立一個對象,打印出來的是多例對象,那麼單例對象和多例對象有什麼區別???
多例每次初始化都會建立一個對象,這樣的話就會出現線程問題,每次獲取到的對象都是不同的,而咱們在servlet和dao層中通常都是採用單例模式
形成建立多例對象的緣由
那麼有什麼辦法能解決這個問題嘛??那就是建立一個Map集合來保存反射建立出來的對象
package com.ithema.jdbc.factory; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * 一個Bean對象的工廠 * Bean在計算機英語中,有可重用組件的含義 * JavaBean:用Java語言編寫的可重用組件 * JavaBean>實體類 * 做用它就是建立咱們使用service和dao對象的 * * 實現方法: * 一、須要一個文件來配置咱們的service和dao * 配置內容:惟一標識=全限定類名(keyvalue) * 二、經過讀取配置文件中配置的內容,反射對象 * * 配置文件能夠是properties或者是xml */ public class Beanfactory { //定義一個properties對象 private static Properties props; //定義一個Map,用於存放咱們建立的對象,咱們把它稱之爲容器 private static Map<String,Object> beans; //使用靜態代碼塊建立Properites對象 static { try { //實例化對象 props=new Properties(); //獲取properites流對象 InputStream in=Beanfactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); //實例化容器 beans=new HashMap<String,Object>(); //取出配置文件中全部的key Enumeration keys=props.keys(); while (keys.hasMoreElements()){ String key=keys.nextElement().toString(); //獲取value值 String beanPath=props.getProperty(key); //建立反射對象 Object value=Class.forName(beanPath).newInstance(); //保存到容器中 beans.put(key,value); } }catch (Exception e){ throw new ExceptionInInitializerError("初始化properties失敗"); } } /** * 根據bean的名稱獲取bean對象 * @param beanName * @return */ public static Object getBean(String beanName) { return beans.get(beanName); } /* public static Object getBean(String beanName) { Object bean=null; try { String beanPath = props.getProperty(beanName); bean = Class.forName(beanPath).newInstance();//經過反射來建立對象,可是每次都會默認調用構造函數建立新的對象 //須要一個容器來保存對象 } catch (Exception e) { e.printStackTrace(); } return bean; }*/ }
再次運行test類Client,獲得就是一個單例對象