解耦 降低程式之間的耦合性
為什麼要降低程式之間的耦合性
**原因很簡單。當耦合度很高時,在代碼維護過程中修改一個地方會涉及到很多地方。如果耦合關系不是澄清修改期間,後果可能是災難性的,特别是對于有許多變化的項目需求和多人協作開發和維護,修改一個地方會導緻子產品的錯誤一直運作穩定,如果是嚴重的,将導緻一個惡性循環,問題永遠不能完全解決,開發和測試正與各種各樣的問題作鬥争。最終會導緻項目延遲,降低使用者滿意度,增加成本。而且也提高了程式的複用性
引入類之間的耦合性
在我們學習jdbc通路資料庫時,具體流程是
首先在maven裡面導入依賴
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
然後就是jdbc的實作過程:
1.注冊驅動
2.擷取連接配接
3.擷取操作資料庫的預處理對象
4.執行SQL,得到結果集
5.周遊結果集
6.釋放資源
具體代碼如下:
public class Jdbc {
public static void main(String[] args) throws Exception{
//1.注冊驅動
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.擷取連接配接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","1234");
//3.擷取操作資料庫的預處理對象
PreparedStatement pstm = conn.prepareStatement("select * from account");
//4.執行SQL,得到結果集
ResultSet rs = pstm.executeQuery();
//5.周遊結果集
while(rs.next()){
System.out.println(rs.getString("name"));
}
//6.釋放資源
rs.close();
pstm.close();
conn.close();
}
}
第一種建立驅動方式
進行分析,上面代碼中被注釋的那句代碼
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
如果把pom裡面的依賴注釋就相當于沒有jar包,然後我們進行編譯
則不能編譯,會是一個錯誤,如圖所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yN1gTO2IWOyQWYzMjY0MmZyYzXxEDO1kDM3EzLchDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
第二種建立驅動方式
Class.forName(“com.mysql.jdbc.Driver”);
這句代碼就隻依賴于一個字元串而不是一個驅動類。
這樣子當jar包不存在時,就是一個異常而不是一個錯誤。這樣子就是避免的類之間的耦合性
但是産生一個新的問題,導緻這個字元串在類中寫死了如果換成其他資料庫的話,就還要改代碼,是以我們要通過配置檔案來擷取要建立的對象全限定類名,然後再用反射來建立對象
是以 解耦的思路:
第一步:使用反射來建立對象,而避免使用new關鍵字。
第二步:通過讀取配置檔案來擷取要建立的對象全限定類名
實際開發中:
應該做到:編譯期不依賴,運作時才依賴。
業務層Service調用持久層Dao時的耦合性
Dao層
userdao層的接口
public interface IUserDao {
void save();
}
userdao層的實作類
package Dao.IMPL;
import Dao.IUserDao;
public class UserDao implements IUserDao {
public void save() {
System.out.println("hello");
}
}
UserService的接口
package Service;
public interface IUserService {
void save();
}
UserService的實作類
package Service.IMPL;
import Dao.IMPL.UserDao;
import Service.IUserService;
public class UserService implements IUserService {
//private将這個對象私有化
//因為dao是一個接口的實作類 接口是不是執行個體化的 但是可以建立一個接口的實作類對象
private IUserDaodao=new UserDao();
public void save() {
System.out.println("hello");
}
}
private IUserDaodao=new UserDao(); 這句代碼就是Service層調用Dao層,當我們把UserDao的代碼去除之後,程式就出現報錯,不能編譯成功,說明程式之間的耦合性太強了。
工廠模式解耦合
上面的service層調用dao層的耦合性太強之後我們可以參考之前的jdbc裡面的步驟。
第一步:使用反射來建立對象,而避免使用new關鍵字。
第二步:通過讀取配置檔案來擷取要建立的對象全限定類名
是以我們可以通過工廠來進行一個解耦
BeanFactory:個建立Bean對象的工廠
什麼是Bean
在計算機英語中,有可重用元件的含義,可重用的意思是一個servlet可能有多個service 一個service中可能有多個dao.一個servicc或者一個dao都是一個Bean.
第一步:需要一個配置檔案來配置我們的service和dao 配置的内容:唯一辨別=全限定類名(key=value)
我們建立一個Bean.properties也可以是一個Bean.xml,在這裡我們在resources裡面建立一個Bean.properties記錄裡面的全限定類名
UserService=Service.IMPL.UserService
UserDao=Dao.IMPL.UserDao
第二步通過讀取配置檔案中配置的内容,反射建立對象
package factory;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class BeanFactory {
//讀取配置檔案
//定義一個靜态Properties對象
private static Properties props;
// //定義一個Map,用于存放我們要建立的對象。我們把它稱之為容器
//多例變單例
private static Map<String,Object> beans;
//使用靜态代碼塊為Properties對象指派
static {
try {
//執行個體化對象
props = new Properties();
//擷取properties檔案的流對象
//這個時候不能用new FileInputStream因為這這個時候的相對路肩和絕對路徑都不管用
//we工程部署src沒有了 相對路徑不能用 絕對路徑也不行
//要用類加載器來進行操作
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
//加載一個流對象
props.load(in);
// //執行個體化容器
beans = new HashMap<String,Object>();
// //取出配置檔案中所有的Key
Enumeration keys = props.keys();
// //周遊枚舉
while (keys.hasMoreElements()){
// //取出每個Key
String key = keys.nextElement().toString();
// //根據key擷取value
String beanPath = props.getProperty(key);
// //反射建立對象
Object value = Class.forName(beanPath).newInstance();
// //把key和value存入容器中
beans.put(key,value);
}
}catch(Exception e){
//抛出一個初始化錯誤 後面直接執行不了
throw new ExceptionInInitializerError("初始化properties失敗!");
}
}
/**
* 根據bean的名稱擷取對象 用Object類型做傳回值
* @param beanName
* @return
*/
public static Object getBean(String beanName){
return beans.get(beanName);
}
這樣之後,我們再調用dao層時就可以把在BeanFactory裡面建立
private IUserDao dao= (IUserDao) BeanFactory.getBean("UserDao");
IUserService service= (IUserService) BeanFactory.getBean("UserService");