二、Spring IoC

一、IoC(Inversion of Control)概述

1. 程序的耦合

耦合性(Coupling),也叫耦合度,是對模塊間關聯程度的度量。耦合的強弱取決於模塊間接口的複雜性、調用模塊的方式以及通過界面傳送數據的多少。模塊間的耦合度是指模塊之間的依賴關係,包括控制關係、調用關係、數據傳遞關係。模塊間聯繫越多,其耦合性越強,同時表明其獨立性越差( 降低耦合性,可以提高其獨立性)。軟件設計中通常用耦合度和內聚度作爲衡量模塊獨立程度的標準。劃分模塊的一個準則就是高內聚低耦合。

一般模塊之間可能的連接方式有七種,構成耦合性的七種類型。它們之間的關係爲(獨立性由強到弱)

  • 非直接耦合(Nondirect Coupling)

如果兩個模塊之間沒有直接關係,它們之間的聯繫完全是通過主模塊的控制和調用來實現的,這就是非直接耦合。這種耦合的模塊獨立性最強。

  • 數據耦合(Data Coupling)

如果一個模塊訪問另一個模塊時,彼此之間是通過數據參數(不是控制參數、公共數據結構或外部變量)來交換輸入、輸出信息的,則稱這種耦合爲數據耦合。由於限制了只通過參數表傳遞數據,按數據耦合開發的程序界面簡單、安全可靠。因此,數據耦合是鬆散的耦合,模塊之間的獨立性比較強。在軟件程序結構中至少必須有這類耦合。

  • 印記耦合(Stamp Coupling)

如果一組模塊通過參數表傳遞記錄信息,就是標記耦合。事實上,這組模塊共享了這個記錄,它是某一數據結構的子結構,而不是簡單變量。這要求這些模塊都必須清楚該記錄的結構,並按結構要求對此記錄進行操作。在設計中應儘量避免這種耦合,它使在數據結構上的操作複雜化了。如果採取“信息隱蔽”的方法,把在數據結構上的操作全部集中。

  • 控制耦合(Control Coupling)

如果一個模塊通過傳送開關、標誌、名字等控制信息,明顯地控制選擇另一模塊的功能,就是控制耦合。這種耦合的實質是在單一接口上選擇多功能模塊中的某項功能。因此,對所控制模塊的任何修改,都會影響控制模塊。另外,控制耦合也意味着控制模塊必須知道所控制模塊內部的一些邏輯關係,這些都會降低模塊的獨立性。

  • 外部耦合(External Coupling)

一組模塊都訪問同一全局簡單變量而不是同一全局數據結構,而且不是通過參數表傳遞該全局變量的信息,則稱之爲外部耦合。例如C語言程序中各個模塊都訪問被說明爲extern類型的外部變量。外部耦合引起的問題類似於公共耦合,區別在於在外部耦合中不存在依賴於一個數據結構內部各項的物理安排。

  • 公共耦合(Common Coupling)

若一組模塊都訪問同一個公共數據環境,則它們之間的耦合就稱爲公共耦合。公共的數據環境可以是全局數據結構、共享的通信區、內存的公共覆蓋區等。這種耦合會引起下列問題:所有公共耦合模塊都與某一個公共數據環境內部各項的物理安排有關,若修改某個數據的大小,將會影響到所有的模塊。
無法控制各個模塊對公共數據的存取,嚴重影響軟件模塊的可靠性和適應性。
公共數據名的使用,明顯降低了程序的可讀性。公共耦合的複雜程度隨耦合模塊的個數增加而顯著增加。若只是兩個模塊之間有公共數據環境,則公共耦合有兩種情況。若一個模塊只是往公共數據環境裏傳送數據,而另一個模塊只是從公共數據環境中取數據,則這種公共耦合叫做鬆散公共耦合。若兩個模塊都從公共數據環境中取數據,又都向公共數據環境裏送數據,則這種公共耦合叫做緊密公共耦合。只有在模塊之間共享的數據很多,且通過參數表傳遞不方便時,才使用公共耦合。否則,還是使用模塊獨立性比較高的數據耦合好些。

  • 內容耦合(Content Coupling)

如果發生下列情形,兩個模塊之間就發生了內容耦合。
一個模塊直接訪問另一個模塊的內部數據;
一個模塊不通過正常入口轉到另一模塊內部;
兩個模塊有一部分程序代碼重疊(只可能出現在彙編語言中);
一個模塊有多個入口。
在內容耦合的情形,所訪問模塊的任何變更,或者用不同的編譯器對它再編譯,都會造成程序出錯

2. 解決程序耦合的思路

  • 使用反射來創建對象,而避免使用new關鍵字。
  • 通過讀取配置文件來獲取要創建類的全限定類名。

3. 工廠模式降低程序的耦合

程序獲取對象的方式由自己創建對象變爲從工廠獲取對象,工廠類通過配置文件去獲取對象的全限定類名

  1. 工廠類
public class BeanFactory {

    private static Properties prop;

    private static Map<String, Object> beans;

    static {
        prop = new Properties();
        beans = new HashMap<>();
        InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            prop.load(is);
            Enumeration<Object> keys = prop.keys();
            // 保證創建的是單例bean
            while (keys.hasMoreElements()) {
                String name = keys.nextElement().toString();
                String path = prop.getProperty(name);
                Object object = Class.forName(path).newInstance();
                beans.put(name, object);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("配置文件初始化失敗!");
        }
    }

    public static <T> T getBean(String beanName) {
        return (T) beans.get(beanName);
    }
}
  1. 配置文件
userDao=com.lizza.dao.UserDao
userService=com.lizza.service.impl.UserServiceImpl
  1. 使用工廠類獲取對象
public class UserController {

    public static void main(String[] args){
        // new創建的對象增加了代碼的耦合度,使用工廠來解耦
        // UserService userService = new UserServiceImpl();
        UserService userService = BeanFactory.getBean("userService");
        userService.saveUser();
    }
}

二、Spring IoC

1. Spring IoC 概述

  • 定義:IoC是指將對象創建的權利交給框架,它包含依賴注入(Dependency Injection)和依賴查找(Dependency Lookup)
  • 作用:降低了程序的耦合

2. 如何使用

  1. 引入依賴
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>
  1. 創建bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userService" class="com.lizza.service.impl.UserServiceImpl"></bean>

    <bean id="userDao" class="com.lizza.dao.UserDao"></bean>

</beans>
  1. 創建容器核心對象
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qxMVyHhs-1583638144634)(http://note.youdao.com/yws/res/17754/98F9AD97B189489291C342E269F77058)]
public class UserController {

    public static void main(String[] args){
        // 1. 創建核心容器對象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        // 2. 獲取對象
        UserService userService = context.getBean("userService", UserService.class);
        userService.saveUser();
    }
}
  1. 獲取bean

3. 深入理解

3.1 ApplicationContext常用的三個實現類

  1. ClassPathXmlApplicationContext:加載類路徑下的配置文件來創建容器
  2. FileSystemXmlApplicationContext:加載磁盤任意位置的配置文件來創建容器
  3. AnnotationConfigApplicationContext:讀取註解創建容器

3.2 BeanFactory 和 ApplicationContext 兩個接口創建對象的時機以及適用場景

在這裏插入圖片描述

接口 創建時機 適用場景
BeanFactory 延遲加載,在需要使用對象的時候才進行創建 多例對象
ApplicationContext 立即加載,容器在初始化的時候立馬創建了對象 單例對象
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章