從shiro源碼角度學習工廠方法設計模式

緒論

shiro是一個簡單易用,功能強大的Java安全框架,學習其源碼設計思想對我們的編碼水平的提高大有裨益。現在,就從源碼角度帶大家學習一下shiro里面的工廠方法模式。 這里的前提是讀者有過使用shiro的基礎,沒有也行,關鍵理解思想就可以了。

從一個簡單例子說起

首先,我們先從一個簡單的例子說起。我們在使用ini文件來作為用戶角色權限配置的時候,我們獲取SecurityManager的方法是:

?Factory<SecurityManager>?factory?=?new?IniSecurityManagerFactory("classpath:demo01_getstarted.ini");
?
?SecurityManager?securityManager?=?factory.getInstance();
復制代碼

上面兩行代碼看似簡單,其實框架底層就使用了工廠方法模式。
關于上面的例子就不多講了。這里是側重分析工廠方法設計模式。

工廠方法模式

在工廠方法模式中,我們對模式角色劃分為四種:
1、抽象產品(產品接口):比如上面shiro實例中的SecurityManager
2、具體產品:比如實現了SecurityManager的類
3、抽象工廠(工廠接口):比如上面shiro實例中的Factory、AbstractFactory
4、具體工廠:比如上面shiro實例中的IniSecurityManagerFactory

我們先來看看shiro里面工廠方法模式實現的源碼:

一、頂級工廠抽象接口Factory,所有抽象工廠類都繼承此接口

public?interface?Factory<T>?{
????T?getInstance();
}
復制代碼

二、抽象工廠類,這個抽象工廠類負責獲取工廠實例,具體創建過程由其子類來實現

public?abstract?class?AbstractFactory<T>?implements?Factory<T>?{

????private?boolean?singleton;
????private?T?singletonInstance;

????public?AbstractFactory()?{
????????this.singleton?=?true;
????}

????public?boolean?isSingleton()?{
????????return?singleton;
????}

????public?void?setSingleton(boolean?singleton)?{
????????this.singleton?=?singleton;
????}
???//?獲取工廠實例,可以以單例形式獲取,也可以每一次獲取都創建一個實例
????public?T?getInstance()?{
????????T?instance;
????????if?(isSingleton())?{
????????????if?(this.singletonInstance?==?null)?{
????????????????this.singletonInstance?=?createInstance();
????????????}
????????????instance?=?this.singletonInstance;
????????}?else?{
????????????instance?=?createInstance();
????????}
????????if?(instance?==?null)?{
????????????String?msg?=?"Factory?'createInstance'?implementation?returned?a?null?object.";
????????????throw?new?IllegalStateException(msg);
????????}
????????return?instance;
????}

????protected?abstract?T?createInstance();
}

復制代碼

上面兩個工廠類抽象了最基本的工廠接口--創建工廠、獲取工廠。如果我們需要對工廠類進行擴展的話,只需要繼承AbstractFactory來實現即可,非常方便。現在看一下AbstractFactory的一個子類。
IniFactorySupport是一個特定的抽象工廠類,是根據ini文件來創建工廠實例的工廠抽象類。我們不需要細究IniFactorySupport代碼干了什么。只需要明白,它是對根據ini文件創建工廠做了一些邏輯處理就好了。
我們可以看到,繼承AbstractFactory,我們可以隨便擴展定制我們工廠類的行為。

public?abstract?class?IniFactorySupport<T>?extends?AbstractFactory<T>?{

????public?static?final?String?DEFAULT_INI_RESOURCE_PATH?=?"classpath:shiro.ini";

????private?static?transient?final?Logger?log?=?LoggerFactory.getLogger(IniFactorySupport.class);

????private?Ini?ini;

????private?Map<String,??>?defaultBeans;

????protected?IniFactorySupport()?{
????}

????protected?IniFactorySupport(Ini?ini)?{
????????this.ini?=?ini;
????}

????public?Ini?getIni()?{
????????return?ini;
????}

????public?void?setIni(Ini?ini)?{
????????this.ini?=?ini;
????}

????protected?Map<String,??>?getDefaults()?{
????????return?defaultBeans;
????}

????public?void?setDefaults(Map<String,??>?defaultBeans)?{
????????this.defaultBeans?=?defaultBeans;
????}

????public?static?Ini?loadDefaultClassPathIni()?{
????????Ini?ini?=?null;
????????if?(ResourceUtils.resourceExists(DEFAULT_INI_RESOURCE_PATH))?{
????????????log.debug("Found?shiro.ini?at?the?root?of?the?classpath.");
????????????ini?=?new?Ini();
????????????ini.loadFromPath(DEFAULT_INI_RESOURCE_PATH);
????????????if?(CollectionUtils.isEmpty(ini))?{
????????????????log.warn("shiro.ini?found?at?the?root?of?the?classpath,?but?it?did?not?contain?any?data.");
????????????}
????????}
????????return?ini;
????}
????
????protected?Ini?resolveIni()?{
????????Ini?ini?=?getIni();
????????if?(CollectionUtils.isEmpty(ini))?{
????????????log.debug("Null?or?empty?Ini?instance.??Falling?back?to?the?default?{}?file.",?DEFAULT_INI_RESOURCE_PATH);
????????????ini?=?loadDefaultClassPathIni();
????????}
????????return?ini;
????}
???
????public?T?createInstance()?{
????????Ini?ini?=?resolveIni();

????????T?instance;

????????if?(CollectionUtils.isEmpty(ini))?{
????????????log.debug("No?populated?Ini?available.??Creating?a?default?instance.");
????????????instance?=?createDefaultInstance();
????????????if?(instance?==?null)?{
????????????????String?msg?=?getClass().getName()?+?"?implementation?did?not?return?a?default?instance?in?"?+
????????????????????????"the?event?of?a?null/empty?Ini?configuration.??This?is?required?to?support?the?"?+
????????????????????????"Factory?interface.??Please?check?your?implementation.";
????????????????throw?new?IllegalStateException(msg);
????????????}
????????}?else?{
????????????log.debug("Creating?instance?from?Ini?["?+?ini?+?"]");
????????????instance?=?createInstance(ini);
????????????if?(instance?==?null)?{
????????????????String?msg?=?getClass().getName()?+?"?implementation?did?not?return?a?constructed?instance?from?"?+
????????????????????????"the?createInstance(Ini)?method?implementation.";
????????????????throw?new?IllegalStateException(msg);
????????????}
????????}

????????return?instance;
????}

????protected?abstract?T?createInstance(Ini?ini);

????protected?abstract?T?createDefaultInstance();
}

復制代碼

通過看類關系圖,IniSecurityManagerFactory繼承IniFactorySupport,在IniFactorySupport基礎上面進一步封裝創建工廠過程。
IniSecurityManagerFactory的源碼就不貼出來了,明白設計思想就可以了。
通過源碼分析,我們可以看到,首先抽象出最基本的工廠接口,具體的工廠類由其子類去實現。一個具體工廠類對應這一類產品。當需要新增產品類的時候,我們只需要新加工廠類,并且新增對應的產品類即可,不需要修改原有工廠類代碼,符合了設計模式中的開閉原則、單一職責原則。

demo實現

一、創建工廠接口:IFactory IFactory.java

/**
?*?泛型代表的是產品類型
?*
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?interface?IFactory<T>?{

????/**
?????*?獲取產品
?????*
?????*?@return?產品實例
?????*/
????T?getInstance();

}

復制代碼

進一步抽象工廠接口 AbstractFactory.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?abstract?class?AbstractFactory<T>?implements?IFactory<T>?{

???/**
????????*?創建產品,具體創建過程由其子類實現
????????*
????????*?@return?創建的產品實例
????????*/
???????protected?abstract?T?createInstance();
???
???????@Override
???????public?T?getInstance()?{
???????????return?createInstance();
???????}
}


復制代碼

二、創建產品接口 IProduct.java


/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?interface?IProduct?{

}

復制代碼

進一步分類產品,創建一類產品接口 Car.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?abstract?class?Car?implements?IProduct?{
????/**
?????*?創建汽車產品
?????*
?????*?@return?創建的汽車產品
?????*/
????protected?abstract?Car?createCar();

????/**
?????*?駕駛汽車
?????*/
????public?abstract?void?drive();
}

復制代碼

具體產品類 Taxi.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?class?Taxi?extends?Car?{

????private?Taxi?taxi;

????@Override
????protected?Car?createCar()?{
????????this.taxi?=?new?Taxi();
????????return?this.taxi;
????}

????@Override
????public?void?drive()?{
????????System.out.println("我是接送客的車");
????}
}
復制代碼

三、創建具體產品的工廠類 TaxtFactory.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?class?TaxiFactory?extends?AbstractFactory<Car>?{

????@Override
????protected?Car?createInstance()?{
????????return?new?Taxi();
????}
}
復制代碼

四、客戶端代碼 Client.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?class?Clent?{
????public?static?void?main(String[]?args)?{
????????IFactory<Car>?factory?=?new?TaxiFactory();
????????Car?taxi?=?factory.getInstance();
????????taxi.drive();
????}
}
復制代碼

通過例子,我們知道,在工廠方法模式中,有一個頂級的產品接口,對產品作出做基本的抽象,然后產品下面還有不同產品的分類,在同一類產品中又有不同的具體產品,比如car類產品下面又會有多種汽車產品。每一個具體的產品都有對應一個具體的工廠類。 如果想再新加一個新的產品,不論是car類產品,還是非car類產品,我們都可以通過新加工廠類和產品類來實現,比如新增一個船類產品

Ship.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?abstract?class?Ship?implements?IProduct?{
????/**
?????*?造船
?????*
?????*?@return
?????*/
????protected?abstract?IProduct?createShip();

????public?abstract?void?doSomething();
}
復制代碼

創建漁船 FishShip.java

/**
?*?漁船
?*
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?class?FishShip?extends?Ship?{

????private?FishShip?ship;

????@Override
????public?IProduct?createShip()?{
????????this.ship?=?new?FishShip();
????????return?this.ship;
????}

????@Override
????public?void?doSomething()?{
????????System.out.println("我在打魚呀");
????}
}

復制代碼

創建漁船工廠類 FishShipFactory.java

/**
?*?@author?wunanliang
?*?@date?2018/1/8
?*?@since?1.0.0
?*/
public?class?FishShipFactory?extends?AbstractFactory<Ship>?{
????@Override
????protected?Ship?createInstance()?{
????????return?new?FishShip();
????}
復制代碼

添加一個產品,我們就得添加產品類和工廠類。對于系統的擴展來說,工廠方法模式有優勢,但是會增加系統的復雜度以及類的數量。

結束語

對于設計模式,大家重點是理解這樣設計的原理與優缺點,不要機械的背誦條條框框。實際我們在開發真實系統時,會糅合多種設計模式在一起。只有我們對設計模式有本質性的認識和掌握,才是真正掌握了設計模式。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284532.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284532.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284532.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

淺談微信小程序對于房地產行業的影響

前幾日&#xff0c;我們曾經整理過一篇文章是關于微信小程序對于在線旅游業的影響的一些反思&#xff08;淺談微信小程序對OTA在線旅游市場的影響&#xff09;&#xff0c;近日由于生活工作的需要走訪了一些房地產的住宅商品房&#xff0c;突然想到微信小程序對于房地產行業會有…

新型基礎測繪與實景三維中國建設技術文件【1】名詞解釋

文章目錄一、新型基礎測繪 new fundamental surveying and mapping**二、實景三維 3D real scene**三、時空大數據平臺 spatio-temporal big data platform**四、地理實體 geo-entity**五、基礎地理實體 fundamental geo-entity**六、組合地理實體數據 combined geo-entity dat…

Android.bp 和 Android.mk 的對應關系

參考 Soong 構建系統 Android.mk 轉為 Android.bp 沒有分支、循環等流程控制的簡單的 Android.mk &#xff0c;可以通過 androidmk 命令轉化為 Android.bp source 、lunch 之后執行即可。 androidmk Android.mk > Android.bp對應關系 Android 13 &#xff0c;build/soon…

深入理解javascript原型和閉包

原文鏈接http://www.cnblogs.com/wangfupeng1988/p/3977924.html 對象是屬性的集合。 function show(x) {console.log(typeof(x)); // undefinedconsole.log(typeof(10)); // numberconsole.log(typeof(abc)); // stringconsole.log(typeof(true)); // booleanconsole.lo…

薪資高壓線

閱讀本文大概需要5分鐘。最近一名讀者咨詢一個問題&#xff1a;洋哥&#xff0c;最近公司有一名同事因為打探其他人薪資被開除了&#xff0c;為啥我們公司要把薪資設置為高壓線。這是個好問題&#xff0c;解答完他的疑惑后想起了一年多前寫過一篇&#xff0c;彼時讀者還比較少&…

達摩院年終預測出爐:2022 十大科技趨勢,AI for Science 高居榜首

作為“一所探索科技未知的研究院”&#xff0c;阿里巴巴達摩院成立至今已經四年了。 這四年來&#xff0c;達摩院秉持著“探索科技位置&#xff0c;以人類愿景為驅動力&#xff0c;開展基礎科學和顛覆式技術創新研究”的原則與使命&#xff0c;在基礎科研和硬科技發展上“遍地生…

chrome調試工具高級不完整使用指南(基礎篇)

一、前言 本文記錄的是作者在工作上面對chrome的一些使用和情況的分析分享&#xff0c;內容僅代表個人的觀點。轉發請注明出處(http://www.cnblogs.com/st-leslie/),謝謝合作 二、瀏覽器模塊介紹 由于chrome瀏覽器一直在不斷的進行更新迭代&#xff0c;會不斷的新增功能&#x…

新型基礎測繪與實景三維中國建設技術文件【2】基礎地理實體分類、粒度及精度基本要求

《新型基礎測繪體系建設試點技術大綱》指出&#xff0c;新型基礎測繪將以“基礎地理實體”為核心的成果模式創新為切入點&#xff0c;帶動技術體系、生產組織體系和政策標準體系的全面創新&#xff0c;從而實現基礎測繪高質量發展。 基礎地理實體作為新型基礎測繪產品體系的核心…

構建和實現單點登錄解決方案(轉載于IBMdeveloperWorks)

將一個開放源碼的基于 Java 的身份驗證組件集成進 Web 門戶中 在現有的應用程序中實現單點登錄解決方案&#xff08;single sign-on&#xff0c;SSO&#xff0c;即登錄一次&#xff0c;就可以向所有網絡資源驗證用戶的身份&#xff09;是非常困難的&#xff0c;但是在構建復雜的…

分享一個基于Abp 和Yarp 開發的API網關項目

這個項目起源于去年公司相要嘗試用微服務構建項目,在網關的技術選型中,我們原本確認了ApiSix 網關,如果需要寫網關插件需要基于Lua腳本去寫,我和另外一個同事當時基于這個寫了一個簡單的插件,但是開發測試以及發布都很麻煩,而且使用Lua腳本作為插件的開發語言本身也不是我們強項…

羅振宇2022“時間的朋友”跨年演講全文稿(pdf)

2021年12月31日20:30&#xff0c;五糧液成都金融城演藝中心&#xff0c;羅振宇“時間的朋友”跨年演講如約而至。 羅胖曾發下大愿望&#xff1a;跨年演講要連辦二十年。今年是第七場&#xff0c;也是最特殊的一場&#xff0c;羅胖面對12000個空座位&#xff0c;用53個好故事&am…

08.LoT.UI 前后臺通用框架分解系列之——多樣的Tag選擇器

LOT.UI分解系列匯總&#xff1a;http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI開源地址如下&#xff1a;https://github.com/dunitian/LoTCodeBase/tree/master/LoTUI 這個必須說下&#xff0c;本來是用Bootstrap-Select做的&#xff0c;很漂亮&#xff0c;正好…

jquery文檔加載完畢后執行的幾種寫法

2019獨角獸企業重金招聘Python工程師標準>>> 1.js文檔加載完畢 標簽內 οnlοad"test()"window.οnlοadfunction(){}2.jquery文檔加載完畢 //方式1 $(document).ready(function(){//TODO }); //方式2 $(function(){//TODO }) //方式3 $(function($){//TO…

新型基礎測繪與實景三維中國建設技術文件【3】基礎地理實體空間身份編碼規則

基礎地理實體是新型基礎測繪產品體系中的核心成果&#xff0c;是推動基礎測繪工作轉型升級的關鍵。與現有的測繪地理信息數據不同&#xff0c;基礎地理實體具有多粒度、多模態、多層次&#xff0c;以及搭載結構化、半結構化和非結構化多樣化信息的鮮明特點。 基礎地理實體空間…

oracle 表 視圖 存儲過程 序列 job

table 表--delete tabledrop table Test1;-- Create tablecreate table TEST1(ID NUMBER,T_NAME VARCHAR2(100),DT DATE);-- 添加注釋comment on column TEST1.T_NAME is 名稱;--添加age字段alter table Test1 add (age NUMBER(8));--刪除字段alter table TABLE_NAME …

[轉]Docker 大勢已去,Podman 即將崛起

Podman Podman 什么是Podman&#xff1f;Podman和Docker的主要區別是什么&#xff1f;Podman的使用與docker有什么區別&#xff1f;Podman 常用命令 容器鏡像部署 PodmanPodman 加速器使用 Podman 運行一個容器列出運行的容器檢查正在運行的容器查看一個運行中容器的日志查看一…

基于Kubernetes v1.24.0的集群搭建(一)

一、寫在前面 K8S 1.24作為一個很重要的版本更新&#xff0c;它為我們提供了很多重要功能。該版本涉及46項增強功能&#xff1a;其中14項已升級為穩定版&#xff0c;15項進入beta階段&#xff0c;13項則剛剛進入alpha階段。此外&#xff0c;另有2項功能被棄用、2項功能被刪除。…

mvc設計模式和mvc框架的區別

一組概念需要先理解&#xff0c;因為后面需要用&#xff1a; 架構&#xff1a;簡單的說架構就是一個藍圖&#xff0c;是一種設計方案&#xff0c;將客戶的不同需求抽象成為抽象組件&#xff0c;并且能夠描述這些抽象組件之間的通信和調用。 框架&#xff1a;軟件框架是項目軟件…

新型基礎測繪與實景三維中國建設技術文件【4】基礎地理實體數據元數據

基礎地理實體數據是新型基礎測繪產品體系中的核心成果&#xff0c;為實現該數據的規范化管理和使用&#xff0c;編制基礎地理實體數據元數據技術文件。本文件規定了基礎地理實體數據元數據的基本要求和元數據內容&#xff0c;適用于二維表達形式、三維表達形式基礎地理實體數據…

思科三層交換機充當路由器實現全網互通

轉載于:https://blog.51cto.com/13568840/2059797