中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

做阿里還是網(wǎng)站濰坊百度關(guān)鍵詞優(yōu)化

做阿里還是網(wǎng)站,濰坊百度關(guān)鍵詞優(yōu)化,政務(wù)網(wǎng)站建設(shè)管理,貴州省建設(shè)廳建筑質(zhì)監(jiān)站網(wǎng)站1.如何對(duì)接口鑒權(quán)這樣一個(gè)功能開(kāi)發(fā)做面向?qū)ο蠓治? 本章會(huì)結(jié)合一個(gè)真實(shí)的案例,從基礎(chǔ)的需求分析、職責(zé)劃分、類(lèi)的定義、交互、組裝運(yùn)行講起,將最基礎(chǔ)的面向?qū)ο蠓治?amp;#xff08;00A)、設(shè)計(jì)(00D)、編程(00P&…

1.如何對(duì)接口鑒權(quán)這樣一個(gè)功能開(kāi)發(fā)做面向?qū)ο蠓治?/h2>

本章會(huì)結(jié)合一個(gè)真實(shí)的案例,從基礎(chǔ)的需求分析、職責(zé)劃分、類(lèi)的定義、交互、組裝運(yùn)行講起,將最基礎(chǔ)的面向?qū)ο蠓治?#xff08;00A)、設(shè)計(jì)(00D)、編程(00P)的套路講清楚,為后面的設(shè)計(jì)原則和設(shè)計(jì)模型打好基礎(chǔ)。

1.1 案例介紹和難點(diǎn)剖析

假設(shè),你參與開(kāi)發(fā)一個(gè)微服務(wù)。微服務(wù)通過(guò) HTTP 暴露接口給其他系統(tǒng)調(diào)用。有一天,你的領(lǐng)導(dǎo)找到你說(shuō),“為了保證接口調(diào)用的安全,希望設(shè)計(jì)實(shí)現(xiàn)一個(gè)接口調(diào)用鑒權(quán)功能,只有經(jīng)過(guò)認(rèn)證的系統(tǒng)才能調(diào)用微服務(wù)接口,沒(méi)有認(rèn)證過(guò)的系統(tǒng)會(huì)被拒絕。希望由你來(lái)開(kāi)發(fā),爭(zhēng)取盡管上線”。

這個(gè)時(shí)候,你可能會(huì)有腦子里一團(tuán)漿糊,一時(shí)間無(wú)從下手的感覺(jué)? 有這種感覺(jué)的原因,個(gè)人覺(jué)得有以下兩點(diǎn)。

1.需求不明確

領(lǐng)導(dǎo)給的需求過(guò)于模糊、籠統(tǒng),離落地到設(shè)計(jì)、編碼還有一定的距離。而人的大腦不擅長(zhǎng)思考這種過(guò)于抽象的問(wèn)題。

前面講過(guò),面向?qū)ο蠓治鲋饕姆治鰧?duì)象是“需求”。因此,面向?qū)ο蠓治隹梢源致缘乜闯伞靶枨蠓治觥?。?shí)際上,不管是需求分析還是面向?qū)ο蠓治?#xff0c;首先要做的是將籠統(tǒng)的需求細(xì)化到足夠清晰、可執(zhí)行。需要通過(guò)溝通、挖掘、分析、假設(shè)、梳理,搞清楚具體的需求有哪些,哪些是現(xiàn)在要做,哪些是未來(lái)可能要做的,哪些是不用考慮的。

2.缺少鍛煉

相比單純的 CRUD 開(kāi)發(fā),鑒權(quán)這個(gè)開(kāi)發(fā)任務(wù)更有難度。鑒權(quán)作為一個(gè)根具體業(yè)務(wù)無(wú)關(guān)的功能,完全可以把它獨(dú)立開(kāi)發(fā)成一個(gè)獨(dú)立的框架,集成到很多業(yè)務(wù)系統(tǒng)中。而作為被很多系統(tǒng)復(fù)用的通用框架,比如普通的代碼,我們對(duì)框架的代碼質(zhì)量要求更高。

開(kāi)發(fā)這樣的通用框架,對(duì)工程師的需求分析能力、設(shè)計(jì)能力、編碼能力,甚至邏輯思維能力的要求,都是比較高的。如果你平時(shí)做的都是簡(jiǎn)單的 CRUD 業(yè)務(wù)開(kāi)發(fā),那這方面的鍛煉肯定不會(huì)很多,所以,一旦遇到這種開(kāi)發(fā)需求,很容易因缺少鍛煉,腦子放空,不知道從何入手,完全沒(méi)有思路。

1.2 對(duì)案例進(jìn)行需求分析

實(shí)際上,需求分析的工作很瑣碎,沒(méi)有固定的方法論。系統(tǒng)通過(guò)這個(gè)例子,給你展示下需求分析時(shí),完整的考慮思路是什么樣的。希望你自己體會(huì),舉一反三地應(yīng)用到其他項(xiàng)目的需求分析中。

針對(duì)鑒權(quán)這個(gè)功能的開(kāi)發(fā),該如何做需求分析?

實(shí)際上,這和做算法題類(lèi)似,先從最簡(jiǎn)單的法案想起,然后再優(yōu)化。所以,我把分析的過(guò)程分為了循序漸進(jìn)的四輪。

第一輪基礎(chǔ)分析

對(duì)于如何鑒權(quán)這樣的問(wèn)題,最簡(jiǎn)單的解決方案是,通過(guò)用戶名加密碼來(lái)做認(rèn)證。我們給每個(gè)允許訪問(wèn)服務(wù)的調(diào)用方,派發(fā)一個(gè) APPID 和一個(gè)對(duì)應(yīng)的密碼。調(diào)用方每次請(qǐng)求時(shí)都攜帶自己的 APPID 和密碼。微服務(wù)在接受到接口調(diào)用請(qǐng)求后,會(huì)解析出 APPID 和密碼,和存儲(chǔ)的 APPID 和密碼進(jìn)行對(duì)比。如果一致則允許調(diào)用請(qǐng)求;否則拒絕調(diào)用。

第二輪分析優(yōu)化

這樣的驗(yàn)證方式,每次都要傳輸明文密碼。密碼很容易被屏蔽,是不安全的。那如果借助加密算法(比如 SHA),對(duì)密碼進(jìn)行加密后,再傳遞到微服務(wù)端驗(yàn)證,是不是就可以了?

實(shí)際上這樣也不安全,因?yàn)榧用苤蟮拿艽a及 APPID,照樣可以被未認(rèn)證系統(tǒng)(或黑客)截獲,未認(rèn)證系統(tǒng)可以攜帶這個(gè)加密之后的面以及對(duì)應(yīng)的 APPID,偽裝成已認(rèn)證系統(tǒng)來(lái)訪問(wèn)我們的接口。這就是典型的“重放攻擊”。

提出問(wèn)題,再解決問(wèn)題,是一個(gè)非常好的迭代方式。對(duì)于剛剛的問(wèn)題,可以借助 OAuth 的驗(yàn)證思路來(lái)解決。 調(diào)用方將請(qǐng)求的 URLAPPID、密碼拼接在一起,然后進(jìn)行加密,生成一個(gè) token 。調(diào)用方在接口請(qǐng)求的時(shí)候,將這個(gè) tokenAPPID,跟著 URL 一塊傳遞給服務(wù)端。服務(wù)端接受到這些數(shù)據(jù)后,根據(jù) APPID 從數(shù)據(jù)庫(kù)中取出對(duì)應(yīng)的密碼,并通過(guò)同樣的 token 生成算法,生成另外一個(gè) token。用這個(gè)新生成的 token 和調(diào)用方傳遞過(guò)來(lái)的 token 對(duì)比。如果一致,則允許接口調(diào)用請(qǐng)求;否則拒絕調(diào)用。

客戶端過(guò)程

1.生成token SHA(http://www.test.com/user?id=123&appid=abc&pwd=def)
2.生成新URLhttp://www.test.com/user?id=123&appid=abc&pwd=def&token=xxx

服務(wù)端過(guò)程

3.解析出 URL、Appid、token
4.從數(shù)據(jù)庫(kù)中根據(jù) Appid 取出 pwd
5.使用同樣的算法生成服務(wù)端 token_s
6. token == token_s,允許訪問(wèn);token != token_s,拒絕訪問(wèn)。

第三輪分析優(yōu)化

經(jīng)過(guò)第二輪優(yōu)化后,仍然存在重放攻擊的風(fēng)險(xiǎn)。因?yàn)槊總€(gè) URL 拼接上 Appid 、密碼生成的 token 都是固定的。

為解決這個(gè)問(wèn)題,可以進(jìn)一步優(yōu)化 token 生成算法,引入一個(gè)隨機(jī)變量,讓每次接口請(qǐng)求生成的 token 都不一樣??梢赃x擇時(shí)間戳作為隨機(jī)變量?,F(xiàn)在使用 URLAppid、密碼、時(shí)間戳四種進(jìn)行加密生成 token。調(diào)用方在進(jìn)行接口請(qǐng)求時(shí),將 token、Appid、時(shí)間戳,隨著 URL 一起傳給微服務(wù)端。

微服務(wù)端在接受到這些數(shù)據(jù)后,會(huì)驗(yàn)證當(dāng)前時(shí)間戳和傳遞過(guò)來(lái)的時(shí)間戳,是否在一定的時(shí)間窗口內(nèi)(如一分鐘)。如果超過(guò)時(shí)間窗口,則判定 token 過(guò)期,拒絕接口請(qǐng)求。如果沒(méi)有超過(guò)時(shí)間窗口,則說(shuō)明 token 沒(méi)有過(guò)期,就在通過(guò)同樣的 token 生成算法,在服務(wù)端生成新的 token,和調(diào)用方的 token 對(duì)比。若一致,則允許接口調(diào)用請(qǐng)求;否則,拒絕調(diào)用。

優(yōu)化后的認(rèn)證流程如下

客戶端流程:

1.生成token SHA(http://www.test.com/user?id=123&appid=abc&pwd=def&ts=156152345)
2.生成新URLhttp://www.test.com/user?id=123&appid=abc&pwd=def&token=xxx&ts=156152345

服務(wù)端流程:

3.解析出 URL、Appid、token
4.驗(yàn)證token是否失效。失效就拒絕訪問(wèn),否則執(zhí)行5
5.從數(shù)據(jù)庫(kù)中根據(jù) Appid 取出 pwd
6.使用同樣的算法生成服務(wù)端 token_s
7. token == token_s,允許訪問(wèn);token != token_s,拒絕訪問(wèn)。

第四輪分析優(yōu)化

不過(guò),你可能會(huì)說(shuō),這樣還是不夠安全呀。未認(rèn)證系統(tǒng)還是可以在一分鐘的 token 失效窗口內(nèi),通過(guò)截取請(qǐng)求,來(lái)調(diào)用我們的借口OA。

你說(shuō)的不錯(cuò)。不過(guò)在攻與防之間,本來(lái)就沒(méi)有絕對(duì)的安全。我們能做的就是,盡量提高攻擊的成本。這個(gè)方案雖然還有漏洞,但是實(shí)現(xiàn)起來(lái)足夠簡(jiǎn)單,而且不會(huì)過(guò)度影響接口本身的性能(比如響應(yīng)時(shí)間)。

實(shí)際上,還有一個(gè)細(xì)節(jié)我們還沒(méi)有考慮到,那就是,如何在微服務(wù)端存儲(chǔ)每個(gè)授權(quán)調(diào)用方的 Appid 和密碼。當(dāng)然,這個(gè)問(wèn)題并不難。最容易想到的方案就是存儲(chǔ)到數(shù)據(jù)庫(kù)里,比如 MySQL。不過(guò),像開(kāi)發(fā)這樣的非業(yè)務(wù)功能,最好不要與具體的第三方系統(tǒng)有過(guò)度的耦合。

針對(duì) Appid 和密碼的存儲(chǔ),最后可以靈活支持不同的存儲(chǔ)方式,比如 Zookeeper、本地配置文件、自研配置中心、MySQL、Redis 等。我們不一定針對(duì)每種存儲(chǔ)都去做實(shí)現(xiàn),但起碼要留有擴(kuò)展點(diǎn),保證系統(tǒng)足夠的靈活性和擴(kuò)展性,能在我們切換存儲(chǔ)方式的時(shí)候,盡可能少的改動(dòng)代碼。

最終確定需求

  • 調(diào)用方進(jìn)行接口請(qǐng)求的時(shí)候,將 URL、Appid、密碼、時(shí)間戳拼接在一起,通過(guò)加密算法生成 token,并將 token、Appid、時(shí)間戳拼接在 URL 中,一并發(fā)送到微服務(wù)端。
  • 微服務(wù)端在接收到調(diào)用方的請(qǐng)求后,從請(qǐng)求中解析出 token、Appid、時(shí)間戳。
  • 微服務(wù)端首先檢查傳遞過(guò)來(lái)的時(shí)間戳是否在 token 失效時(shí)間窗口內(nèi)。若已失效,則接口調(diào)用鑒權(quán)失敗,拒絕接口調(diào)用請(qǐng)求
  • 如果 token 沒(méi)有過(guò)期失效,微服務(wù)再?gòu)淖约旱拇鎯?chǔ)中,取出 Appid 對(duì)應(yīng)的密碼,通過(guò)同樣的 token 生成算法,生成另一個(gè) token,與調(diào)用方的 token 進(jìn)行比對(duì)。如果一致,則鑒權(quán)成功,允許接口調(diào)用;否則就拒絕接口調(diào)用。

這就是我們的需求分析的整個(gè)過(guò)程,從最粗糙、最模型的需求開(kāi)始,通過(guò)“提出問(wèn)題 - 再解決問(wèn)題”的方式,循序漸進(jìn)的方式進(jìn)行優(yōu)化,最后得到一個(gè)足夠清晰、可落地的需求描述。

2.如何利用面向?qū)ο笤O(shè)計(jì)和編程開(kāi)發(fā)接口鑒權(quán)功能?

2.1如何進(jìn)行面向?qū)ο笤O(shè)計(jì)(OOD)

面向?qū)ο蠓治龅漠a(chǎn)出是詳細(xì)的需求描述,面向?qū)ο笤O(shè)計(jì)的產(chǎn)出是類(lèi)。在面向?qū)ο笤O(shè)計(jì)環(huán)節(jié),我們將需求描述轉(zhuǎn)化成具體的類(lèi)的設(shè)計(jì)。

設(shè)計(jì)這一環(huán)節(jié)拆解細(xì)化,主要包含以下幾個(gè)部分:

  • 劃分職責(zé)而識(shí)別出有哪些類(lèi)
  • 定義類(lèi)及其屬性和方法
  • 定義類(lèi)之間的交互關(guān)系
  • 將類(lèi)組裝起來(lái)并提供執(zhí)行入口

劃分職責(zé)而識(shí)別出有哪些類(lèi)

根據(jù)需求描述,把其中涉及的功能點(diǎn),一個(gè)個(gè)羅列出來(lái),然后再去看看哪些功能職責(zé)相近,操作同樣的屬性,是否應(yīng)該歸為同一個(gè)類(lèi)。

我們來(lái)看下,針對(duì)鑒權(quán)這個(gè)例子,具體如何來(lái)做。之前我們依據(jù)確定了最終需求,如下:

  • 調(diào)用方進(jìn)行接口請(qǐng)求的時(shí)候,將 URL、Appid、密碼、時(shí)間戳拼接在一起,通過(guò)加密算法生成 token,并將 tokenAppid、時(shí)間戳拼接在 URL 中,一并發(fā)送到微服務(wù)端。
  • 微服務(wù)端在接收到調(diào)用方的請(qǐng)求后,從請(qǐng)求中解析出 token、Appid、時(shí)間戳。
  • 微服務(wù)端首先檢查傳遞過(guò)來(lái)的時(shí)間戳是否在 token 失效時(shí)間窗口內(nèi)。若已失效,則接口調(diào)用鑒權(quán)失敗,拒絕接口調(diào)用請(qǐng)求
  • 如果 token 沒(méi)有過(guò)期失效,微服務(wù)再?gòu)淖约旱拇鎯?chǔ)中,取出 Appid 對(duì)應(yīng)的密碼,通過(guò)同樣的
    token 生成算法,生成另一個(gè) token,與調(diào)用方的 token 進(jìn)行比對(duì)。如果一致,則鑒權(quán)成功,允許接口調(diào)用;否則就拒絕接口調(diào)用。

首先是逐字逐句地閱讀上面的需求,拆解成一個(gè)個(gè)小的功能點(diǎn),一條條羅列下來(lái)。注意,拆解出來(lái)的每個(gè)功能點(diǎn)要盡可能小。每個(gè)功能點(diǎn)只負(fù)責(zé)一個(gè)很小的事情(專業(yè)叫法是“單一職責(zé)”)。下面是逐句拆解下來(lái)后,得到的功能點(diǎn)羅列:

  1. URL、Appid、密碼、時(shí)間戳拼接為一個(gè)字符串
  2. 對(duì)字符串通過(guò)加密算法加密得到 token
  3. token、Appid、時(shí)間戳拼接在 URL 中,形成新的 URL
  4. 解析得到 token、Appid、時(shí)間戳等信息
  5. 根據(jù)時(shí)間戳判斷 token 是否過(guò)期失效
  6. 從存儲(chǔ)中取出 Appid 對(duì)應(yīng)的密碼
  7. 驗(yàn)證兩個(gè) token 是否匹配

從上面的功能列表中,我們發(fā)現(xiàn) 1、2、5、7 都是和 token 相關(guān),負(fù)責(zé) token 的生成、驗(yàn)證。3、4 都是在處理 URL,負(fù)責(zé) URL 的拼接和解析;6 是操作 Appid 和密碼,負(fù)責(zé)從存儲(chǔ)中讀取 Appid 和密碼。所以,我們可以粗略地得到三個(gè)核心類(lèi):AuthToken 、URL、CredentialStorage

  • AuthToken 負(fù)責(zé) 1、2、5、7 這四個(gè)操作。
  • URL 負(fù)責(zé) 3、4 這兩個(gè)操作。
  • CredentialStorage 負(fù)責(zé) 6 這個(gè)操作。

當(dāng)然,這是一個(gè)初步的類(lèi)劃分,其他一些不重要的類(lèi),我們可能暫時(shí)沒(méi)有辦法一下子想全,但這也沒(méi)關(guān)系,面向?qū)ο蠓治?、設(shè)計(jì)、編程本來(lái)就是一個(gè)循環(huán)迭代、不斷優(yōu)化的過(guò)程。根據(jù)需求,我們先給出一個(gè)粗糙版本的設(shè)計(jì)方案,然后基于這樣一個(gè)基礎(chǔ),再去迭代優(yōu)化,會(huì)更加容易些,思路也更加清晰一些。

需要強(qiáng)調(diào)一點(diǎn),接口調(diào)用鑒權(quán)這個(gè)需求比較簡(jiǎn)單,所以需求對(duì)應(yīng)的面向?qū)ο笤O(shè)計(jì)并不復(fù)雜,識(shí)別出來(lái)的類(lèi)也不多。如果是面向的更加大型的軟件開(kāi)發(fā)、更加復(fù)雜的需求,涉及的功能點(diǎn)可能會(huì)很多,對(duì)應(yīng)的類(lèi)也會(huì)比較多,像剛剛那樣根據(jù)需求逐句羅列功能點(diǎn)的方法,最后會(huì)得到一個(gè)很長(zhǎng)的列表,就會(huì)優(yōu)點(diǎn)凌亂、沒(méi)有規(guī)律。

針對(duì)這種復(fù)雜的需求開(kāi)發(fā),首先要做的是進(jìn)行模塊劃分,將需求先簡(jiǎn)單劃分成幾個(gè)小的、獨(dú)立的功能模塊,然后再在模塊內(nèi)部,應(yīng)用剛剛的方法,進(jìn)行面向?qū)ο笤O(shè)計(jì)。而模塊的劃分和識(shí)別,跟類(lèi)的劃分和識(shí)別,是類(lèi)似的套路。

定義類(lèi)及其屬性和方法

通過(guò)剛剛的需求分析,識(shí)別出了三個(gè)核心類(lèi):AuthTokenURL、CredentialStorage?,F(xiàn)在再來(lái)看下,每個(gè)類(lèi)有哪些屬性和方法。我們還是從功能點(diǎn)列表中挖掘。

AuthToken 類(lèi)相關(guān)的功能點(diǎn)有四個(gè):
  • URLAppid、密碼、時(shí)間戳拼接為一個(gè)字符串
  • 對(duì)字符串通過(guò)加密算法加密得到 token
  • 根據(jù)時(shí)間戳判斷 token 是否過(guò)期失效
  • 驗(yàn)證兩個(gè) token 是否匹配

對(duì)于方法的識(shí)別,一般都是識(shí)別需求描述中的動(dòng)詞,作為候選方法,再進(jìn)一步過(guò)濾篩選。類(lèi)比下方法的識(shí)別,可以把功能點(diǎn)中涉及的名詞,作為候選屬性,然后同樣進(jìn)行過(guò)濾篩選。

借用這個(gè)思路,識(shí)別出 AuthToken 類(lèi)的屬性和方法

/****** AuthToken ******/
// 屬性
private static final long DEFAULT_EXPIRED_TIME_INTERVAL = 60000;
private String token;
private long createTime;
private long expiredTimeInterval = DEFAULT_EXPIRED_TIME_INTERVAL;// 構(gòu)造函數(shù)
public AuthToken(String token, long createTime);
public AuthToken(String token, long createTime, long expiredTimeInterval);// 函數(shù)
public static AuthToken create(String baseUrl, long createTime, Map<String, String> params;)
public String getToken();
public boolean isExpired();
public boolean match(AuthToken authToken);

從上面的類(lèi)中,我們可以返現(xiàn)這樣三個(gè)小細(xì)節(jié):

  • 第一個(gè)細(xì)節(jié): 并不是所有出現(xiàn)的名詞都被定義為類(lèi)的屬性,比如 URL、Appid、密碼、時(shí)間戳這幾個(gè)名詞,我們把它作為了方法的參數(shù)。
  • 第二個(gè)細(xì)節(jié):我們還需要挖掘出一些沒(méi)有出現(xiàn)在功能點(diǎn)描述中的屬性,比如 createTimeexpiredTimeInterval,它們用在 isExpired() 函數(shù)中用來(lái)判斷 token 是否過(guò)期。
  • 第三個(gè)細(xì)節(jié):我們還給 AuthToken 類(lèi)添加了一個(gè)功能點(diǎn)描述中沒(méi)有提到的方法 getToken()。

第一個(gè)細(xì)節(jié)高速我們,從業(yè)務(wù)模型上來(lái)說(shuō),不應(yīng)該屬于這個(gè)類(lèi)的屬性和方法,不應(yīng)該被放到這個(gè)類(lèi)中。比如 URL、Appid 這些信息,從業(yè)務(wù)模型上來(lái)說(shuō),不應(yīng)該屬于 AuthToken ,所以不應(yīng)該放到這個(gè)類(lèi)中。

第二、第三個(gè)細(xì)節(jié)高速我們,在設(shè)計(jì)類(lèi)具體有哪些屬性和方法的時(shí)候,不能單純地依賴當(dāng)下的需求,還要分析這個(gè)類(lèi)從業(yè)務(wù)模型上來(lái)講,應(yīng)該具有哪些屬性和方法。這樣一方面保證類(lèi)定義的完整性,另一方面不僅為當(dāng)下的需求,還為未來(lái)的需求做些準(zhǔn)備。

Url 類(lèi)相關(guān)的功能點(diǎn)有兩個(gè)
  • tokenAppid、時(shí)間戳拼接在 URL 中,形成新的 URL
  • 解析得到 tokenAppid、時(shí)間戳等信息

雖然需求描述中,都是以 URL 來(lái)代指接口請(qǐng)求,但是,接口請(qǐng)求并不一定是 URL 的形式來(lái)表達(dá),還可能是 DubboRPC 等其他形式。為了讓這個(gè)類(lèi)設(shè)計(jì)的更加通用,命名更加貼切,我們接下來(lái)把它命名為 ApiRequest。下面是根據(jù)功能點(diǎn)描述設(shè)計(jì)的 ApiRequest

/****** ApiRequest ******/// 屬性
private String baseUrl;
private String token;
private String appId;
private long timestamp;// 構(gòu)造函數(shù)
public ApiRequest(String baseUrl, String token,String appId, long timestamp);// 函數(shù)
public static ApiRequest createFromUrl(String url);public String getBaseUrl();
public String getToken();
public String getAppId();
public long getTimestamp();
CredentialStorage 類(lèi)相關(guān)的功能點(diǎn)有一個(gè)
  • 從存儲(chǔ)中取出 Appid 對(duì)應(yīng)的密碼
    CredentialStorage 類(lèi)很簡(jiǎn)單。為了做到抽象封裝具體的存儲(chǔ)方式,我們將 CredentialStorage 設(shè)計(jì)成了接口,基于接口而非實(shí)現(xiàn)編程。
/****** CredentialStorage ******/// 接口函數(shù)
String getPasswordByAppId(String appId);

定義類(lèi)之間的交互關(guān)系

類(lèi)與類(lèi)之間的關(guān)系有哪些? UML 統(tǒng)一建模語(yǔ)言定義了 6 種類(lèi)之間的關(guān)系。分別是:泛化、實(shí)現(xiàn)、關(guān)聯(lián)、聚合、組合、依賴。

泛化可以簡(jiǎn)單理解為繼承關(guān)系。

public class A {...}
public class B extends A {...}

實(shí)現(xiàn)一般是指接口和實(shí)現(xiàn)類(lèi)之間的關(guān)系。

public interface A {...}
public class B implements A {...}

聚合 是一種包含關(guān)系,A 類(lèi)對(duì)象包含 B 類(lèi)對(duì)象,B 類(lèi)對(duì)象的生命周期可以不依賴 A 類(lèi)對(duì)的生命周期,也就是說(shuō)可以單獨(dú)銷(xiāo)毀 A 類(lèi)對(duì)象而不影響 B 類(lèi)對(duì)象,比如課程與學(xué)生的關(guān)系。

public class A {private B b;public A(B b) {this.b = b;}
}

組合也是一種包含的關(guān)系。A 類(lèi)對(duì)象包含 B 類(lèi)對(duì)象,B 類(lèi)對(duì)象的生命周期依賴 A 類(lèi)對(duì)的生命周期,B 類(lèi)對(duì)象不可以單獨(dú)存在,比如鳥(niǎo)與翅膀的關(guān)系。

public class A {private B b;public A() {this.b = new B();}
}

關(guān)聯(lián) 是一種比較弱的關(guān)系,包含組合和聚合。如果 B 類(lèi)對(duì)象是 A 類(lèi)的成員變量,那 B 類(lèi)和 A 類(lèi)就是關(guān)聯(lián)關(guān)系。

public class A {private B b;public A(B b) {this.b = b;}
}或者public class A {private B b;public A() {this.b = new B();}
}

依賴是一種比關(guān)聯(lián)關(guān)系更加弱的關(guān)系,包含關(guān)聯(lián)關(guān)系。不管 B 類(lèi)對(duì)象是 A 類(lèi)的成員變量,還是 A 類(lèi)的方法使用 B 類(lèi)對(duì)象作為入?yún)ⅰ⒎祷刂?、局部變?#xff0c;只要 B 類(lèi)對(duì)象和 A 類(lèi)對(duì)象有任何使用關(guān)系,都稱它們具有依賴關(guān)系。

public class A {private B b;public A(B b) {this.b = b;}
}或者public class A {private B b;public A() {this.b = new B();}
}或者public class A {public void func(B b) {...}
}

個(gè)人覺(jué)得這樣拆分的太細(xì),增加了學(xué)習(xí)的成本,對(duì)指導(dǎo)編程沒(méi)有太大的意義。所以,我只保留了四個(gè)關(guān)系:泛化、實(shí)現(xiàn)、組合、依賴。其中泛化、實(shí)現(xiàn)、依賴的定義不變,組合關(guān)系替代 UML 中的組合、聚合、關(guān)聯(lián)這三個(gè)概念。

相當(dāng)于重命名關(guān)聯(lián)關(guān)系為組合關(guān)系,且不在區(qū)分組合和聚合這兩個(gè)概念。
只要 B 類(lèi)對(duì)象,是 A 類(lèi)的成員變量,那就成 A 類(lèi)和 B 類(lèi)具有組合關(guān)系。

在看下我們定義的類(lèi)之間有哪些關(guān)系?因?yàn)槟壳爸挥腥齻€(gè)核心類(lèi),所以只用到了實(shí)現(xiàn)關(guān)系,即 CredentialStorageMySqlCredentialStorage 之間是實(shí)現(xiàn)關(guān)系。接下來(lái)講到組裝類(lèi)的時(shí)候,還會(huì)用到依賴關(guān)系、組合關(guān)系,但是泛化關(guān)系暫時(shí)沒(méi)有用到。

將類(lèi)組裝起來(lái)并提供執(zhí)行入口

類(lèi)定義好了,類(lèi)之間的泛化關(guān)系也設(shè)計(jì)好了,接下來(lái)我們要將所有的類(lèi)組裝在一起,提供一個(gè)執(zhí)行入口。這個(gè)入口可能是 main() 函數(shù),也可能是一組給外部用的 API 接口。通過(guò)這個(gè)入口,我們能觸發(fā)整個(gè)代碼跑起來(lái)。

接口鑒權(quán)并不是一個(gè)獨(dú)立運(yùn)行的系統(tǒng),而是一個(gè)集成在系統(tǒng)上運(yùn)行的組件,所以,我們封裝所有的實(shí)現(xiàn)細(xì)節(jié),設(shè)計(jì)一個(gè)最頂層的 ApiAuthenticator 接口類(lèi),暴露一組給外部調(diào)用者或者 API 接口,作為觸發(fā)執(zhí)行鑒權(quán)邏輯的入口。

/****** ApiAuthenticator ******/
// 接口函數(shù)
void auth(String url);
void auth(ApiRequest apiRequest);

實(shí)現(xiàn)類(lèi)

/****** DefaultApiAuthenticatorImpl ******/
// 屬性
private CredentialStorage credentialStorage;
// 構(gòu)造函數(shù)
public DefaultApiAuthenticatorImpl();
public DefaultApiAuthenticatorImpl(CredentialStorage credentialStorage);
// 函數(shù)
void auth(String url);
void auth(ApiRequest apiRequest);

2.2 如何進(jìn)行面向?qū)ο缶幊?#xff08;OOP)

面向?qū)ο笤O(shè)計(jì)完成之后,已經(jīng)定義了清晰的類(lèi)、屬性、方法、類(lèi)之間的交互,并將所有的類(lèi)組裝起來(lái),提供了統(tǒng)一的執(zhí)行入口。接下來(lái),面向?qū)ο缶幊痰墓ぷ?#xff0c;就是將這些設(shè)計(jì)思路翻譯成代碼實(shí)現(xiàn)。有了前面分析,這部分工作相對(duì)來(lái)說(shuō)就比較簡(jiǎn)單了。所以,這里,只給出比較復(fù)雜的 ApiAuthenticator 的實(shí)現(xiàn)。

對(duì)于 AuthToken、ApiRequestCredentialStorage 這三個(gè)類(lèi),就不給出具體代碼實(shí)現(xiàn)了。你可以自己試著把整個(gè)鑒權(quán)框架自己實(shí)現(xiàn)一遍。

public interface ApiAuthenticator {void auth(String url);void auth(ApiRequest apiRequest);
}public class DefaultApiAuthenticatorImpl implements ApiAuthenticator {private CredentialStorage credentialStorage;public DefaultApiAuthenticatorImpl() {this.credentialStorage = new MysqlCredentialStorage();}public DefaultApiAuthenticatorImpl(CredentialStorage credentialStorage) {this.credentialStorage = credentialStorage;}@Overridevoid auth(String url) {ApiRequest apiRequest = ApiRequest.createFromUrl(url);auth(apiRequest);}@Overridevoid auth(ApiRequest apiRequest) {String appId = apiRequest.getAppId();String token = apiRequest.getToken();long timestamp = apiRequest.getTimestamp();String baseUrl = apiRequest.getBaseUrl();AuthToken clientAuthToken = new AuthToken(token, timestamp);if(clientAuthToken.isExpired()) {throw new RuntimeException("Token is exipred.");}String password = credentialStorage.getPasswordByAppId(appId);AuthToken serverAuthToken = AuthToken.generator(baseUrl, appId, password, timestamp);if(!serverAuthToken.match(clientAuthToken)) {throw new RuntimeException("Token verfication failed.");}}
}

2.3 辯證思考與靈活應(yīng)用

之前講解過(guò),面向?qū)ο蠓治?、設(shè)計(jì)、編程,每個(gè)環(huán)節(jié)的界限劃分都比較清楚。而且,設(shè)計(jì)和實(shí)現(xiàn)基本上是按照功能點(diǎn)的描述,逐句照著翻譯過(guò)來(lái)的。這樣做的好處是先做什么,后做什么,都非常清晰、明確。

不過(guò)在平時(shí)的工作中,大部分程序員往往都是在腦子里或者草紙上完成面向?qū)ο蠓治龊驮O(shè)計(jì)后,然后就開(kāi)始寫(xiě)了,邊寫(xiě)邊思考重構(gòu),并不會(huì)嚴(yán)格地按照剛剛的流程來(lái)執(zhí)行。而且,說(shuō)實(shí)話,即使在寫(xiě)代碼之前,花很多時(shí)間做分析和設(shè)計(jì),繪制出完美的類(lèi)圖、UML 圖,也不可能把每個(gè)細(xì)節(jié)、交互都想的很清楚。在落實(shí)到代碼的時(shí)候,還是要反復(fù)迭代、重構(gòu)、打破重寫(xiě)。

畢竟,整個(gè)軟件開(kāi)發(fā)本來(lái)就是一個(gè)迭代、修修補(bǔ)補(bǔ)、遇到問(wèn)題解決問(wèn)題的過(guò)程,是一個(gè)不斷重構(gòu)的過(guò)程。我們沒(méi)法嚴(yán)格地按照順序執(zhí)行各個(gè)步驟。

2.4 總結(jié)回顧

面向?qū)ο蠓治龅漠a(chǎn)出是詳細(xì)的需求描述。面向?qū)ο笤O(shè)計(jì)的產(chǎn)出是類(lèi)。在面向?qū)ο笤O(shè)計(jì)這一環(huán)節(jié),我們將需求描述轉(zhuǎn)化為具體的類(lèi)的設(shè)計(jì)。這個(gè)環(huán)節(jié)的工作可以分為四步:

  1. 劃分職責(zé)進(jìn)而識(shí)別出有哪些類(lèi)
    根據(jù)需求描述,把其中涉及的功能點(diǎn),一個(gè)個(gè)羅列出來(lái),然后再去看哪些功能點(diǎn)職責(zé)相近,操作同樣的屬性,可否歸為一個(gè)類(lèi)。
  2. 定義類(lèi)的屬性和方法
    識(shí)別出功需求中的動(dòng)詞,作為候選方法,再進(jìn)一步過(guò)濾篩選出真正的方法;把功能點(diǎn)中涉及的名詞,作為候選屬性,然后再同樣進(jìn)行過(guò)濾篩選。
  3. 定義類(lèi)與類(lèi)之間的關(guān)系
    UML 統(tǒng)一建模語(yǔ)言定義了六種類(lèi)之間的關(guān)系。分別是:泛化、實(shí)現(xiàn)、關(guān)聯(lián)、組合、聚合、依賴。從貼近編程的角度,我們對(duì)類(lèi)之間的關(guān)系做了調(diào)整,保留四個(gè)關(guān)系:泛化、實(shí)現(xiàn)、組合、依賴。
  4. 將類(lèi)封裝起來(lái)并提供執(zhí)行入口
    將所有類(lèi)組裝在一起,提供一個(gè)執(zhí)行入口。這個(gè)入口可能是 main() 函數(shù),也可能是一組給外部調(diào)用的 API 接口。通過(guò)這個(gè)接口,我們能觸發(fā)整個(gè)代碼跑起來(lái)。
http://www.risenshineclean.com/news/64510.html

相關(guān)文章:

  • 微商網(wǎng)站制作武漢關(guān)鍵詞排名推廣
  • 哪些網(wǎng)站可以找到做海報(bào)的素材鄭州seo網(wǎng)站排名
  • xxx網(wǎng)站策劃書(shū)西安網(wǎng)頁(yè)設(shè)計(jì)
  • 莫名接到網(wǎng)站建設(shè)電話推廣引流工具
  • 溫嶺做網(wǎng)站新冠疫情最新消息今天
  • 營(yíng)銷(xiāo)型網(wǎng)站建設(shè)實(shí)戰(zhàn)》杭州優(yōu)化公司哪家好
  • 中國(guó)建設(shè)銀行的業(yè)務(wù)范圍深圳百度網(wǎng)站排名優(yōu)化
  • 日照疫情最新消息今天封城了廣州網(wǎng)絡(luò)seo公司
  • 個(gè)人網(wǎng)站備案 淘寶客天氣預(yù)報(bào)最新天氣預(yù)報(bào)
  • 心理咨詢網(wǎng)站開(kāi)發(fā)長(zhǎng)春網(wǎng)站建設(shè)制作
  • 坪山做網(wǎng)站的公司北京全網(wǎng)營(yíng)銷(xiāo)推廣
  • 網(wǎng)站建設(shè)分幾模塊黃頁(yè)推廣引流網(wǎng)站
  • 哪些網(wǎng)站可以做調(diào)查賺錢(qián)優(yōu)化推廣網(wǎng)站seo
  • 網(wǎng)站建設(shè)公司有哪些方面微商怎么引流被加精準(zhǔn)粉
  • 怎么注冊(cè)英文網(wǎng)站域名互動(dòng)營(yíng)銷(xiāo)的案例及分析
  • 免費(fèi)建立個(gè)人文章網(wǎng)站百度游戲風(fēng)云榜
  • c2c商城網(wǎng)站建設(shè)費(fèi)用b站推廣入口2023年
  • 句容網(wǎng)站建設(shè)制作萬(wàn)網(wǎng)查詢
  • 網(wǎng)站的鏈接結(jié)構(gòu)怎么做營(yíng)銷(xiāo)策劃書(shū)模板范文
  • 典型的電子商務(wù)網(wǎng)站有哪些太原seo哪家好
  • 廣州做網(wǎng)站信科分公司南京今日新聞?lì)^條
  • 重慶承越網(wǎng)站建設(shè)公深圳抖音seo
  • 廈門(mén)市建設(shè)廳網(wǎng)站網(wǎng)絡(luò)推廣的平臺(tái)
  • 個(gè)人靜態(tài)網(wǎng)站首頁(yè)怎么做百度sem推廣具體做什么
  • 網(wǎng)站開(kāi)發(fā)職業(yè)技能簡(jiǎn)歷營(yíng)銷(xiāo)管理系統(tǒng)
  • 移動(dòng)電商網(wǎng)站推廣普通話標(biāo)語(yǔ)
  • 湖州做網(wǎng)站建設(shè)的公司哪家好關(guān)鍵詞優(yōu)化推廣
  • 淘寶優(yōu)惠券查詢網(wǎng)站怎么做深圳網(wǎng)絡(luò)推廣外包公司
  • 酒店和網(wǎng)站對(duì)接如何做app推廣平臺(tái)網(wǎng)站
  • 招生代理平臺(tái)seo如何去做優(yōu)化