研磨設計模式之裝飾模式 1

2021-08-25 10:10:57 字數 2721 閱讀 6919

考慮這樣乙個實際應用:就是如何實現靈活的獎金計算。

獎金計算是相對複雜的功能,尤其是對於業務部門的獎金計算方式,是非常複雜的,除了業務功能複雜外,另外乙個麻煩之處是計算方式還經常需要變動,因為業務部門經常通過調整獎金的計算方式來激勵士氣。

先從業務上看看現有的獎金計算方式的複雜性:

看了上面獎金計算的問題,所幸我們只是來學習設計模式,並不是真的要去實現整個獎金計算體系的業務,因此也沒有必要把所有的計算業務都羅列在這裡,為了後面演示的需要,簡化一下,演示用的獎金計算體系如下:

乙個人的獎金分成很多個部分,要實現獎金計算,主要就是要按照各個獎金計算的規則,把這個人可以獲取的每部分獎金計算出來,然後計算乙個總和,這就是這個人可以得到的獎金。

(1)為了演示,先準備點測試資料,在記憶體中模擬資料庫,示例**如下:

/**

* 在記憶體中模擬資料庫,準備點測試資料,好計算獎金

*/public class tempdb

/*** 記錄每個人的月度銷售額,只用了人員,月份沒有用

*/public static mapmapmonthsalemoney =

new hashmap();

static

}

(2)按照獎金計算的規則,實現獎金計算,示例**如下:

/**

* 計算獎金的物件

*/public class prize

return prize;

} /**

* 計算某人的當月業務獎金,引數重複,就不再注釋了

*/private double monthprize(string user, date begin, date end)

/*** 計算某人的累計獎金,引數重複,就不再注釋了

*/public double sumprize(string user, date begin, date end)

/*** 判斷人員是普通人員還是業務經理

* @param user 被判斷的人員

* @return true表示是業務經理,false表示是普通人員

*/private boolean ismanager(string user)

return false;

} /**

* 計算當月團隊業務獎,引數重複,就不再注釋了

*/public double groupprize(string user, date begin, date end)

double prize = group * 0.01;

system.out.println(user+"當月團隊業務獎金"+prize);

return prize;

}}

(3)寫個客戶端來測試一下,看看是否能正確地計算獎金,示例**如下:

public class client 

}

測試執行的結果如下: 

張三當月業務獎金300.0

張三累計獎金1000.0

**********張三應得獎金:1300.0

李四當月業務獎金600.0

李四累計獎金1000.0

**********李四應得獎金:1600.0

王五當月業務獎金900.0

王五累計獎金1000.0

王五當月團隊業務獎金600.0

**********王經理應得獎金:2500.0

看了上面的實現,挺簡單的嘛,就是計算方式麻煩點,每個規則都要實現。真的很簡單嗎?仔細想想,有沒有什麼問題?

對於獎金計算,光是計算方式複雜,也就罷了,不過是實現起來會困難點,相對而言還是比較好解決的,不過是用程式把已有的演算法表達出來。

最痛苦的是,這些獎金的計算方式,經常發生變動,幾乎是每個季度都會有小調整,每年都有大調整,這就要求軟體的實現要足夠靈活,要能夠很快進行相應調整和修改,否則就不能滿足實際業務的需要。

舉個簡單的例子來說,現在根據業務需要,需要增加乙個「環比增長獎金」,就是本月的銷售額比上個月有增加,而且要達到一定的比例,當然增長比例越高,獎金比例越大。那麼軟體就必須要重新實現這麼個功能,並正確的新增到系統中去。過了兩個月,業務獎勵的策略發生了變化,不再需要這個獎金了,或者是另外換了乙個新的獎金方式了,那麼軟體就需要把這個功能從軟體中去掉,然後再實現新的功能。

那麼上面的要求該如何實現呢?

很明顯,一種方案是通過繼承來擴充套件功能;另外一種方案就是到計算獎金的物件裡面,新增或者刪除新的功能,並在計算獎金的時候,呼叫新的功能或是不呼叫某些去掉的功能,這種方案會嚴重違反開-閉原則。

還有乙個問題,就是在執行期間,不同人員參與的獎金計算方式也是不同的,舉例來說:如果是業務經理,除了參與個人計算部分外,還要參加團隊獎金的計算,這就意味著需要在執行期間動態來組合需要計算的部分,也就是會有一堆的if-else。

總結一下,獎金計算面臨如下問題:

上面描述的獎金計算的問題,絕對沒有任何誇大成分,相反已經簡化不少了,還有更多麻煩沒有寫上來,畢竟我們的重點在設計模式,而不是業務。

把上面的問題抽象一下,設若有乙個計算獎金的物件,現在需要能夠靈活的給它增加和減少功能,還需要能夠動態的組合功能,每個功能就相當於在計算獎金的某個部分。

現在的問題就是:如何才能夠透明的給乙個物件增加功能,並實現功能的動態組合呢?

也可以直接在卓越網上搜尋《研磨設計模式》

未完待續

研磨設計模式之橋接模式 1

來寫乙個大家既陌生又熟悉的設計模式,也是非常實用的乙個設計模式,那就是橋接模式。說陌生是很多朋友並不熟悉這個設計模式,說熟悉是很多人經常見到或者是下意識的用到這個設計模式,只是不知道罷了。橋接模式是非常實用的乙個模式,下面就來寫寫它。考慮這樣乙個實際的業務功能 傳送提示訊息。基本上所有帶業務流程處理...

研磨設計模式之命令模式 3

可撤銷操作的意思就是 放棄該操作,回到未執行該操作前的狀態。這個功能是乙個非常重要的功能,幾乎所有gui應用裡面都有撤消操作的功能。gui的選單是命令模式最典型的應用之一,所以你總是能在選單上找到撤銷這樣的選單項。既然這麼常用,那該如何實現呢?有兩種基本的思路來實現可撤銷的操作,一種是補償式,又稱反...

設計模式之裝飾設計模式

1.目的 動態擴充套件類的行為 開閉原則 對擴充套件開放,對修改關閉 2.要點 裝飾類和被裝飾類都實現同乙個介面或者繼承同乙個類 3.具體實現 被裝飾元件介面 被裝飾元件實現類實現 抽象類構建被裝飾元件實現被裝飾元件介面 裝飾類繼承抽象類 裝飾類 重寫抽象類方法 裝飾 4.例項 被裝飾類介面 pub...