解耦的實際應用 許可權設計

2022-04-17 07:59:20 字數 2931 閱讀 3160

系統設計乙個很重要的目的就是為了重用﹐而要做到重用﹐低耦合是最有效的手段。

本文將通過web應用系統中乙個最常見的主題--許可權設計﹐來說明解耦的應用。

要解耦﹐首先就要進行抽象﹐許可權究竟能不能抽象?

我認為通常意義上的許可權應該分為2類﹕

一類是使用者是否有權進行某項動作﹐如管理員可以刪貼﹐人事考勤員可以修改考勤資料。這種許可權就是最簡單的有或無問題﹐毫無疑問﹐這是可以抽象出來單獨進行設計的。

當然這種許可權應用也可以進行抽象﹐但是其耦合程度相對較高﹐抽象後進行的重用是在coding級別的﹐比如封裝了許可權的分配﹐移除和獲取**﹐但是需要new 乙個許可權類﹐並在業務系統中使用該許可權類。

本文著重通過第一類許可權的應用的說明來闡述解耦的應用.

第一類許可權其實是應用最為廣泛的許可權﹐對此類許可權設計最常見的就是分角色﹐如乙個bbs﹐有管理員﹐斑竹﹐普通使用者﹐匿名使用者4種角色。每個人員是一種角色﹐每種角色可訪問的選單﹐頁面或按鈕是不一樣的。

一些小型的﹐邏輯相對簡單﹐應用已穩定的系統使用此種方法可大大減化許可權的設計。

但是它畢竟是耦合的。

舉個最簡單的例子﹐例如在貼子列表頁面上﹐斑竹可能在每個貼子後面會多乙個刪除按鈕﹐而普通使用者則不會有此按鈕。程式設計師經常需要這樣編碼﹕

if(user is 管理員 或 斑竹)

刪除按鈕.visible = true

else

刪除按鈕.visible = false

乍看這樣的**﹐是看不到有什麼問題的。但至少有一點ugly的就是出現了程式設計師最忌諱的hardcode**:user is 管理員 或 斑竹﹐可能有人說這一點點不會有太大影響。

但是這至少讓我們的系統有了如下的假定﹕

1﹕只有管理員或斑竹才能刪除貼子﹐這種假設是很難站住腳的﹐系統不斷變化﹐很容易哪天出現了乙個"代斑竹"或"副斑竹"的角色﹐它們也可以刪貼...

2﹕系統建立在這幾種固定的角色之上﹐相信除了這個頁面的判斷角色**外﹐系統的其它地方一定也會充斥這樣的**﹐一旦要改﹐那就只好將此類**全部找出來...

一旦這些假設變化了﹐系統就會被這種耦合」拖累」

在我幾年的程式設計生涯裡﹐碰到的這種許可權修改要求可謂數不勝數﹐某個主管打**過來﹐能不能幫我開放一下考勤查詢許可權﹐我想看到我們部門的考勤狀況。天啦﹐考勤查詢是考勤員才能查的呀﹐開放這個給他可以呀﹐但更多的只有人事考勤員才能操作的功能都"不安全"的暴露在他面前了﹐誰知道它會不會去點點裡面的哪個按鈕?

你也許會說﹐當初開發程式時﹐需求分析就應該做清楚﹐現在請按正常的系統維護流程來做。

不單說他是主管﹐也可能是客戶﹐我們就無法拒絕。

更重要最終我們還要是改程式﹐還是要面對哪些散落在系統各個角落的許可權判斷**﹐為什麼當初我們就不留下乙個心眼呢?

解決的方法就是將許可權抽象﹐與具體的業務系統解耦﹐開發系統的時候完全不去考慮這個系統有哪些角色﹐他們哪些人可以做什麼﹐哪些人又可以做什麼。而是將這部分需求撇開。

比如我們在編寫刪除貼子的**時﹐就完全不用寫下

if(has 刪除許可權)

//刪除貼子**

而是直接就寫刪除﹐我管你有沒有刪除許可權﹐但你**既然執行到了這裡﹐那我假定你肯定就有刪貼子的許可權﹐至於你是管理員﹐斑竹﹐副斑竹﹐甚至是普通使用者我也不管﹐也許你高興﹐讓某個普通使用者也暫時可以刪貼子(客戶或主管要求嘛)

這樣我們就把整個系統的功能全部開發出來了。

現在﹐任何人進入系統﹐映入它眼簾的就是所有選單﹐所有按鈕﹐太舒服了。

好了﹐現在我們再來考慮使用者的許可權要求吧﹕

使用者要求分4種角色﹕管理員﹐斑竹﹐普通使用者﹐匿名使用者

管理員什麼事情都可以做

斑竹只可以刪貼

普通使用者可以撤斑竹

匿名使用者只能進入瀏覽頁面

建幾個表﹐做一下對應﹐然後寫乙個方法﹐傳入userid和功能﹐返回true或false就可以了(我以前的貼子有介紹過一種具體的方案)。

這個許可權管控放在**呢?

很簡單﹐只要不要和你的業務**放在一起就可以了﹐也許你可以通過aop這種時髦的方式來完成﹐或者最簡單的﹐就寫乙個類﹐在每次呼叫方法時﹐統一判斷許可權。

在web系統中就最簡單了﹐只要做乙個訪問的url和功能的對應關係﹐然後利用乙個httpmodule在每次request時﹐先把url轉換成功能﹐然後再呼叫上述許可權判斷方法﹐返回true就進﹐false就轉向錯誤頁面。

可以看出﹐我們的應用系統很乾淨﹐我們的許可權模組也很乾淨。

最後再提一下﹐在這種許可權方案做web頁面時經常碰到的一種情形﹐就是我剛剛提到的同乙個頁面可能有不同許可權的情形﹐你無論如何都迴避不了那行

if(user is 管理員 或 斑竹)

刪除按鈕.visible = true

else

刪除按鈕.visible = false

的**。

是這樣的

但是換過乙個角度我們就能理解了﹐我們不把這種許可權看作業務邏輯﹐我現在只是在提供功能﹐需要提供2種功能﹐瀏覽和管理﹐那好﹐我寫兩支程式。一支show.aspx﹐一支manage.aspx

別人會說你有病

確實有病﹐明明是差不多完全一樣的**﹐為什麼要寫兩支程式﹐這不找抽嗎?

沒辦法﹐我就寫一支程式

postlist.aspx

但是兩個功能的訪問位址分別是﹕

post.aspx?type=show

post.aspx?type=manage

那行**也巧妙地變為了﹕

if(request["type"]=="manage")

刪除按鈕.visible = true

else if(request["type"] == "show")

刪除按鈕.visible = false

這樣你就看到了﹐程式設計師在寫這個頁面的**時﹐完全佔據了主動﹐再也不會去問系統分析師﹕老大﹐究竟誰才有刪貼子的許可權呢?

而只要對老大說﹐老大﹐你要的程式已經寫好了﹐瀏覽和管理的頁面分別是...

你愛怎麼用就怎麼用吧﹐什麼? 許可權? 管我什麼事?

呵呵﹕)

就到這裡﹐歡迎討論。

**--

關於解耦的思考

前言 以前記得在知乎上看過,乙個神奇的例子,大致上來說就是乙個手機接觸到了金屬湯匙,結果手機顯示檢測的未知裝置。其實從一方面看來這也算是乙個 復用的思想吧。在設計程式的時候,我們都會盡力提高 的復用性,這也導致在方法中會產生依賴的關係,但是對於使用者而言,依賴關係會新增諸多的限制,因此在設計程式的時...

解耦的簡單理解

重用性是物件導向設計的主要目標之一,而緊耦合便是它的敵人。當我們看到系統中乙個元件的改變迫使系統其他許多地方也發生改變的時候,就可以診斷為緊耦合了。簡單實現 class registrationmgr abstract class notifier else abstract function in...

對於解耦的理解

以三層為例子 在bll層中建立dal層的某個物件 iuserdal userdal dalabstractfactory.createuserdal 即層之間的關聯降到最低,這樣我們很容易想到引用乙個第三方來作為中間介質。這就引出了介面,在層中要建立其他層的某個物件時,用介面來接收這個物件,這個介面...