spring中使用了哪些設計模式

spring中使用了哪些設計模式

相信大家對spring都很熟悉,使用都是好多年了,但是大家對它有多瞭解呢,它爲什麼好用?爲什麼這麼靈活?帶着這些問題我們一起來研究,發現設計模式的落地讓它變得優雅靈活,好用,下面我們來介紹一下它使用的9種設計模式吧。

第一種:簡單工廠

又叫做靜態工廠方法(StaticFactory Method)模式,但不屬於23種GOF設計模式之一。 
簡單工廠模式的實質是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類。 
spring中的BeanFactory就是簡單工廠模式的體現,根據傳入一個唯一的標識來獲得bean對象,
但是否是在傳入參數後創建還是傳入參數前創建這個要根據具體情況來定。
如下配置,就是在 HelloIController類中創建一個 testBean。
<beans>
    <bean id="singletonBean" class="com.itpengwei.HelloIController">
        <constructor-arg>
            <value>Hello! 這是singletonBean!value>
        </constructor-arg>
   </ bean>
    <bean id="testBean" class="com.itpengwei.HelloIController"
        singleton="false">
        <constructor-arg>
            <value>Hello! 這是testBean! value>
        </constructor-arg>
    </bean>
</beans>

第二種:工廠方法(Factory Method)

通常由應用程序直接使用new創建新的對象,爲了將對象的創建和使用相分離,採用工廠模式,即應用程序將對象的創建及初始化職責交給工廠對象。
一般情況下,應用程序有自己的工廠對象來創建bean.如果將應用程序自己的工廠對象交給Spring管理,那麼Spring管理的就不是普通的bean,而是工廠Bean。
這裏就以工廠方法中的靜態方法爲例講解一下:
import java.util.Random;
public class StaticFactoryBean {
      public static Integer createRandom() {
           return new Integer(new Random().nextInt());
       }
}
建一個config.xm配置文件,將其納入Spring容器來管理,需要通過factory-method指定靜態方法名稱
<bean id="random"
class="com.itpengwei.StaticFactoryBean" factory-method="createRandom" />
<!--createRandom方法必須是static的,才能找到 scope="prototype"-->

測試:

public static void main(String[] args) {
      //調用getBean()時,返回隨機數.如果沒有指定factory-method,會返回StaticFactoryBean的實例,即返回工廠Bean的實例       
      XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("config.xml"));      
      System.out.println("我是IT學習者創建的實例:"+factory.getBean("random").toString());
}

第三種:單例模式(Singleton)

當我們試圖從Spring容器中取得某個類的實例時,默認情況下,Spring會才用單例模式進行創建。
如果我不想使用默認的單例模式,每次請求我都希望獲得一個新的對象怎麼辦呢?很簡單,將scope屬性值設置爲prototype(原型)就可以了
<bean id="date" class="java.util.Date" scope="prototype"/>
//或者
Controller(scope="prototype")
....
通過以上配置信息,Spring就會每次給客戶端返回一個新的對象實例。
那麼Spring對單例的底層實現,到底是餓漢式單例還是懶漢式單例呢?
Spring框架對單例的支持是採用單例註冊表的方式進行實現的

第四種:適配器(Adapter)

在Spring的Aop中,使用的Advice(通知)來增強被代理類的功能。Spring實現這一AOP功能的原理就使用代理模式
(1、JDK動態代理。2、CGLib字節碼生成技術代理。)對類進行方法級別的切面增強,即,生成被代理類的代理類,
 並在代理類的方法前,設置攔截器,通過執行攔截器重的內容增強了代理方法的功能,實現的面向切面編程。
Adapter類接口:Target
public interface AdvisorAdapter {
boolean supportsAdvice(Advice advice);
      MethodInterceptor getInterceptor(Advisor advisor);
 
} MethodBeforeAdviceAdapter類,Adapter
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
      public boolean supportsAdvice(Advice advice) {
            return (advice instanceof MethodBeforeAdvice);
      }
 
      public MethodInterceptor getInterceptor(Advisor advisor) {
            MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
      return new MethodBeforeAdviceInterceptor(advice);
      }
 
}

第五種:包裝器(Decorator)

在我們的項目中遇到這樣一個問題:我們的項目需要連接多個數據庫,
而且不同的客戶在	每次訪問中根據需要會去訪問不同的數據庫。
我們以往在spring和hibernate框架中總是配置一個數據源,因而sessionFactory的dataSource屬性總是指向這個數據源並且恆定不變,所有DAO在使用sessionFactory的時候都是通過這個數據源訪問數據庫。
但是現在,由於項目的需要,我們的DAO在訪問sessionFactory的時候都不得不在多個數據源中不斷切換,
問題就出現了:如何讓sessionFactory在執行數據持久化的時候,根據客戶的需求能夠動態切換不同的數據源?我們能不能在spring的框架下通過少量修改得到解決?是否有什麼設計模式可以利用呢? 
首先想到在spring的applicationContext中配置所有的dataSource。
這些dataSource可能是各種不同類型的,比如不同的數據庫:Oracle、SQL Server、MySQL等,也可能是不同的數據源:
比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。
然後sessionFactory根據客戶的每次請求,將dataSource屬性設置成不同的數據源,以到達切換數據源的目的。
spring中用到的包裝器模式在類名上有兩種表現:一種是類名中含有Wrapper,另一種是類名中含有Decorator。
基本上都是動態地給一個對象添加一些額外的職責。

第六種:代理(Proxy)

爲其他對象提供一種代理以控制對這個對象的訪問。  
從結構上來看和Decorator模式類似,但Proxy是控制,更像是一種對功能的限制,而Decorator是增加職責。 
spring的Proxy模式在aop中有體現,比如JdkDynamicAopProxy和Cglib2AopProxy。 

第七種:觀察者(Observer)

定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。
spring中Observer模式常用的地方是listener的實現。如ApplicationListener。 

第八種:策略(Strategy)

定義一系列的算法,把它們一個個封裝起來,並且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。 
spring中在實例化對象的時候用到Strategy模式
在SimpleInstantiationStrategy中有如下代碼說明了策略模式的使用情況:
![源碼](https://img-blog.csdnimg.cn/20190126103247565.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3B3MTkxNDEwMTQ3,size_16,color_FFFFFF,t_70)

第九種:模板方法(Template Method)

定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。
Template Method使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
Template Method模式一般是需要繼承的。
這裏想要探討另一種對Template Method的理解。
spring中的JdbcTemplate,在用這個類時並不想去繼承這個類,因爲這個類的方法太多,	
但是我們還是想用到JdbcTemplate已有的穩定的、公用的數據庫連接,那麼我們怎麼辦呢?
我們可以把變化的東西抽出來作爲一個參數傳入JdbcTemplate的方法中。
但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量。
怎麼辦?那我們就用回調對象吧。在這個回調對象中定義一個操縱JdbcTemplate中變量的方法,我們去實現這個方法,就把變化的東西集中到這裏了。
然後我們再傳入這個回調對象到JdbcTemplate,從而完成了調用。
這可能是Template Method不需要繼承的另一種實現方式吧。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章