- 兩個核心:反轉控制 IoC (Inverse of Control),面向切面程式設計 AOP (Aspect Oriented Programming)
- 優勢:
- 方便程式解耦,簡化開發過程
- AOP 程式設計支援(解決 OOP 實現不了的功能)
- 宣告式事務支援
- 方便程式測試
- 方便整合各種框架
- 降低 JavaEE API 使用難度
解耦
程式碼解釋程式間的耦合
一個模擬儲存賬戶的應用
持久層介面: spring/selflearning/dao/IAccountDao.java
package spring.selflearning.dao;
/*
持久層
*/
public interface IAccountDao {
/*
模擬儲存賬戶
*/
void saveAccount();
}
持久層實現類: spring/selflearning/dao/impl/AccountDaoImpl.java
package spring.selflearning.dao.impl;
import spring.selflearning.dao.IAccountDao;
/*
賬戶持久層實現類
*/
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("儲存了賬戶");
}
}
業務層介面: spring/selflearning/service/IAccountService.java
package spring.selflearning.service;
public interface IAccountService {
/*
業務層介面
*/
void saveAccount();
}
業務層實現類: spring/selflearning/service/impl/AccountServiceImpl.java
此處由於需要透過新建物件的方式呼叫持久層,所以與持久層有依賴關係,一旦持久層被更改,程式將報錯。
package spring.selflearning.service.impl;
import spring.selflearning.dao.IAccountDao;
import spring.selflearning.dao.impl.AccountDaoImpl;
import spring.selflearning.service.IAccountService;
/*
賬戶業務層實現類
*/
public class AccountServiceImpl implements IAccountService {
// 業務層呼叫持久層
private IAccountDao accountDao = new AccountDaoImpl(); // 業務層由於new了持久層實現類,具有強耦合性
public void saveAccount() {
accountDao.saveAccount();
}
}
表現層: spring/selflearning/ui/Client.java
表現層也需要新建業務層物件,所以有依賴關係。
package spring.selflearning.ui;
import spring.selflearning.dao.IAccountDao;
import spring.selflearning.service.IAccountService;
import spring.selflearning.service.impl.AccountServiceImpl;
/*
模擬表現層,用於呼叫業務層
*/
public class Client {
public static void main(String[] args) {
IAccountService as = new AccountServiceImpl(); // 表現層由於new了業務層實現類,具有強耦合性
as.saveAccount();
}
}
解耦的思路
- 用反射建立物件,避免使用 new 關鍵字
- 讀取配置檔案獲取要建立的物件全限定類名 (方便更改依賴包)
使用工廠模式解耦
- 工廠模式做了什麼?
- 為了解耦,我們使用一個建立 Bean 物件的工廠
- Bean 是可重用元件,持久層可以被業務層重用,業務層可以被表現層重用,因此在上面的程式碼示例中可以建立業務層和持久層物件
- 步驟:使用一個配置檔案配置service和dao,然後透過讀取配置檔案內容反射建立物件。配置檔案(.xml 或 .properties)的內容是 service 和 dao 的全限定類名。
利用工廠模式讀取配置程式碼示例: spring/selflearning/factory/BeanFactory.java
這段程式碼利用 BeanFactory 讀取配置檔案,並自定義了獲取可重用元件物件的方法。
package spring.selflearning.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
// Bean: 可重用元件
public class BeanFactory {
private static Properties props;
// 為 props 物件賦值
static {
props = new Properties(); // 例項化物件
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); // 不使用 new 建立流物件而使用getClassLoader()是為了防止配置檔案位置的更改。
try {
props.load(in);
} catch (IOException e) {
throw new ExceptionInInitializerError("初始化Properties失敗!");
}
}
// 根據 Bean 的名稱獲取 Bean 物件
public 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;
}
}
配置檔案: resources/bean.properties
accountService=spring.selflearning.service.impl.AccountServiceImpl
accountDao=spring.selflearning.dao.impl.AccountDaoImpl
表現層解耦: spring/selflearning/ui/Client.java
package spring.selflearning.ui;
//import spring.selflearning.dao.IAccountDao;
import spring.selflearning.factory.BeanFactory;
import spring.selflearning.service.IAccountService;
//import spring.selflearning.service.impl.AccountServiceImpl;
/*
模擬表現層,用於呼叫業務層
*/
public class Client {
public static void main(String[] args) {
// IAccountService as = new AccountServiceImpl(); // 表現層由於new了業務層實現類,具有強耦合性
IAccountService as = (IAccountService) BeanFactory.getBean("accountService"); // 解耦,將getBean()得到的Object類強轉為所需型別
as.saveAccount();
}
}
業務層解耦: spring/selflearning/service/impl/AccountServiceImpl.java
package spring.selflearning.service.impl;
import spring.selflearning.dao.IAccountDao;
//import spring.selflearning.dao.impl.AccountDaoImpl;
import spring.selflearning.factory.BeanFactory;
import spring.selflearning.service.IAccountService;
/*
賬戶業務層實現類
*/
public class AccountServiceImpl implements IAccountService {
// 業務層呼叫持久層
// private IAccountDao accountDao = new AccountDaoImpl(); // 業務層由於new了持久層實現類,具有強耦合性
private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao"); // 解耦,將getBean()得到的Object類強轉為所需型別
public void saveAccount() {
accountDao.saveAccount();
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結