java框架學習日誌-2

上篇文章(java框架學習日誌-1)雖然跟着寫了例子,也理解爲何這麼寫,可是有個疑問,爲何叫控制反轉?控制的是什麼?反轉又是什麼?
控制其實就是控制對象的建立。
反轉與正轉對應,正轉是由程序自己來建立對象,而反轉就是程序自己不建立對象。而是被動地接收對象。
上篇文章雖然把對象的建立這一步移至客戶端,可是終究仍是由程序來建立對象的。Spring提供了一個Ioc容器,能夠用它來建立對象,在spring中,全部java類都是資源,全部資源都是Bean,管理這些Bean的就是Spring提供的Ioc容器。
若是不使用Ioc容器去生成對象,那麼全部對象都要靠程序自己建立,若是測試人員要測試一個類,就要本身去構建這個類,和這個類所依賴的其餘類,可是測試人員對構建對象並不熟悉,並且也會加大工做量。
若是不使用Ioc容器會怎麼樣呢?舉個例子,咱們若是要吃飯,那麼就要本身煮飯,本身作菜,本身作飲料。這就是主動去建立對象,可是在有了Ioc容器後,Ioc容器就像飯店,咱們只須要描述本身須要什麼,而後就不用關注作飯的具體過程,而後等飯端上來就行了,這就是被動地接收對象,下面是代碼演示。java

主動建立對象

首先須要一個鍋,而後準備米飯,飲料,肉。spring

public class Pan {

    /**
     *鍋
     * @param rice 加米飯
     * @param juice 喝什麼飲料
     * @param meat 吃什麼肉
     * @return 成品
     */
    public String cooking(String rice,String juice,String meat){
        String food=rice+"配"+meat+",再喝點"+juice;
        return food;
    }
}

而後是烹飪過程,須要new一個鍋,傳入米飯等參數的具體值編程

public class FoodMaker {
    private Pan pan=new Pan();
    private String rice;
    private String juice;
    private String meat;

    public String getRice() {
        return rice;
    }

    public void setRice(String rice) {
        this.rice = rice;
    }

    public String getJuice() {
        return juice;
    }

    public void setJuice(String juice) {
        this.juice = juice;
    }

    public String getMeat() {
        return meat;
    }

    public void setMeat(String meat) {
        this.meat = meat;
    }

    public String makefood(){
        return pan.cooking(rice,juice,meat);
    }
}

最後測試一下設計模式

public class Test {
    public static void main(String[] args) {
        FoodMaker foodMaker=new FoodMaker();
        foodMaker.setRice("白米飯");
        foodMaker.setJuice("可樂");
        foodMaker.setMeat("黃燜雞");
        String food=foodMaker.makefood();
        System.out.println(food);
    }
}


而後用被動建立對象來實現上面的代碼。框架

被動建立對象

在寫代碼以前須要先導入相關jar包,這個能夠去spring官網下載,既然要用bean去管理java類,那麼就須要一個bean的xml文件,在src目錄下新建xml文件

既然用的別人的東西,那麼就須要導入頭文件,spring的頭文件,模板以下,如今不用管爲何這麼寫,複製就對了,以前提到過,bean就是java對象,由spring容器來建立和管理,這裏的name能夠換成id。id是惟一的,name是別名。class就是類的全限定名,包括位置,由於我這裏沒寫包,因此就只是類名。property就是類裏的參數,value就是參數的值。在教學視頻中bean的name和類名都是hello,後面要用到hello的時候我分不清楚傳的究竟是哪一個,因此這裏我就用了不同的名字。工具

<?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
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean name="cooking" class="FoodMaker">
        <property name="rice" value="土豆飯"/>
        <property name="juice" value="紅茶"/>
        <property name="meat" value="小炒肉"/>
    </bean>
</beans>

而後就能夠測試一下了學習

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        //解析beans.xml文件,生成相應對象,傳入bean容器的名字
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
        FoodMaker foodMaker=(FoodMaker)context.getBean("cooking");//cooking就是FoodMaker的別名
        System.out.println(foodMaker.makefood());
    }
}

結果。注意結果是經過commons logging打印的,這個須要的jar包一樣在spring裏面。
測試

從結果上來看,兩種寫法是同樣的,可是經過spring來實現代碼,就不須要程序來建立對象,對象是由spring容器建立的,對象的屬性是由spring容器來設置的。這麼一個過程就叫控制反轉。這樣的話,若是之後須要添加對象,就不用修改代碼,能夠直接經過bean容器來管理和建立對象,好比再添加一頓飯就能夠這樣添加。ui

<?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
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean name="cooking" class="FoodMaker">
        <property name="rice" value="土豆飯"/>
        <property name="juice" value="紅茶"/>
        <property name="meat" value="小炒肉"/>
    </bean>
    <bean name="cooking2" class="FoodMaker">
        <property name="rice" value="炒飯"/>
        <property name="juice" value="肥仔快樂水"/>
        <property name="meat" value="肥仔快樂堡"/>
    </bean>
</beans>

測試結果

控制反轉還有個名字叫依賴注入。在上面的例子中,依賴指的是FoodMaker對rice,juice,meat的依賴。而rice等屬性的值是由容器給的,這叫依賴注入,實際上是一個東西,只是看的角度不同。this

總結

其實ioc是一種編程思想,它的目的也是遵循了設計模式中的下降程序耦合度,方便拓展,避免修改。上面例子中是將對象的建立脫離出程序自己,讓spring去完成,其實這只是一方面,主要思想是將主動編程變成被動接受。本身去new對象也是主動編程,接收對象也是接收資源。 Ioc的實現是經過ioc容器實現的,ioc容器就是bean工廠(由於bean能夠建立不少對象,並且因此也叫bean工廠。bean工廠其實也是工廠模式,只是這種工廠模式是由spring提供,以前看設計模式,覺得這些設計模式都要本身寫,原來也有輪子能夠用,好比單例模式,只要在beans.xml裏的class="FoodMaker"後面加上scope="single"。代碼以下

<bean name="cooking" class="FoodMaker" scope="singleton">
        <property name="rice" value="土豆飯"/>
        <property name="juice" value="紅茶"/>
        <property name="meat" value="小炒肉"/>
    </bean>

上面的例子其實使用bean來建立對象還不夠完全,在FoodMaker類裏面,還有個Pan對象是咱們手動建立的。以前在只是簡單的給一些String屬性賦值,那若是是複雜一點的對象怎麼賦值呢?代碼以下:
修改在FoodMaker的代碼,讓pan的值爲null,生成set,get方法,經過set,get方法來給pan賦值。

private Pan pan=null;
    private String rice;
    private String juice;
    private String meat;

    public Pan getPan() {
        return pan;
    }

    public void setPan(Pan pan) {
        this.pan = pan;
    }

beans.xml佈置文件以下,其中ref是引用對象,由spring建立。之後若是添加其餘烹飪工具,只須要用spring建立對象,而後傳入ref就能夠了。就不須要改變代碼了。

<?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
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="pan" class="Pan"/>
    <bean name="cooking" class="FoodMaker">
        <property name="rice" value="土豆飯"/>
        <property name="juice" value="紅茶"/>
        <property name="meat" value="小炒肉"/>
        <property name="pan" ref="pan"></property>
    </bean>
</beans>

注意!!!

public class FoodMaker {
    private Pan pan=null;//id=「pan」的pan不是這裏的pan。
    private String rice;
    private String juice;
    private String meat;

    public Pan getPan() {
        return pan;
    }

    public void setPan(Pan pan) {//注意在beans文件中,id=「pan」中的pan,其實setPan中的Pan首字母小寫。
        this.pan = pan;
    }

若是這裏setPan改爲setPPP,那麼beans文件裏相應的id也要改爲pPP,因此必定要注意書寫規範,我在寫這個例子的時候,由於寫xml文件時不會實時糾錯,而系統給的錯誤信息又太多看不懂,因此排錯排了好久,才發現是大小寫錯了。最後再測試一下這個代碼,運行結果和以前同樣,就不貼圖了。

相關文章
相關標籤/搜索