暑期自學 Day 15 | Spring (一)

Borris發表於2020-05-30
  • 兩個核心:反轉控制 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 協議》,轉載必須註明作者和本文連結

相關文章