09、策略模式

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

策略模式與工廠模式最大的區別在于,策略模式注重的是對算法的維護,也可以理解為對算法的封裝。而工廠模式,則只是負責創建類,在剛接觸策略模式時候,往往與工廠模式容易產生混淆。
官方對策略模式的解釋:
它定義了算法家族,分別封裝起來,讓他們之間可以互換,此模式,讓算法的變化不會影響到使用算法的客戶。

從此模式開始,每次總結的時候畫出一個UML圖。

此例子結合商場搞活動銷售活動,商品價格打折、以及返價活動。
任何一種活動,最終都要有一個計算結果的方法,所以對此方法進行抽象:
   
  1. public interface PriceCalculate {
  2. public abstract double getFinalPrice();
  3. }
然后對其進行實現,分別為不搞活動,折扣,返現活動,分別如下:
   
  1. public class NormalPrice implements PriceCalculate {
  2. private double finalPrice = 0d;
  3. public double getFinalPrice() {
  4. // TODO Auto-generated method stub
  5. return finalPrice;
  6. }
  7. public NormalPrice(double sourcePrice){
  8. this.finalPrice = sourcePrice;
  9. }
  10. }
然后是折扣活動:
   
  1. public class DebetPrice implements PriceCalculate {
  2. private double finalPrice = 0d;
  3. @Override
  4. public double getFinalPrice() {
  5. return finalPrice;
  6. }
  7. public DebetPrice(double sourcePrice,double debet){
  8. this.finalPrice = Calculate.mul(sourcePrice, debet);
  9. }
  10. }
Calculate為工具類,具體代碼在最后。
然后是折現活動:
    
  1. public class ReturnPrice implements PriceCalculate {
  2. private double finalPrice = 0d;
  3. @Override
  4. public double getFinalPrice() {
  5. // TODO Auto-generated method stub
  6. return finalPrice;
  7. }
  8. /**滿多少價反錢活動
  9. * @param sourcePrice 原價
  10. * @param conditionPrice 返現金消費額度
  11. * @param returnPrice 返現金力度
  12. */
  13. public ReturnPrice(double sourcePrice,double conditionPrice,double returnPrice){
  14. this.finalPrice = sourcePrice;
  15. if( sourcePrice >= conditionPrice ){
  16. double times = Math.floor(Calculate.div(sourcePrice, conditionPrice)) ;
  17. int count = times>=1? (int)times:0;
  18. while(count-->0){
  19. this.finalPrice = Calculate.sub(sourcePrice,returnPrice);
  20. }
  21. }
  22. }
  23. }


其中的Calculate為工具類,具體如下:
   
  1. package com.yp.learn.util;
  2. import java.math.BigDecimal;
  3. public class Calculate {
  4. // 默認除法運算精度
  5. private static final int DEF_DIV_SCALE = 10;
  6. private Calculate(){};
  7. /**精確 加法運算
  8. * @param d1 被加數
  9. * @param d2 加數
  10. * @return 和
  11. */
  12. public static double add(double d1,double d2){
  13. BigDecimal b1= new BigDecimal(Double.toString(d1));
  14. BigDecimal b2= new BigDecimal(Double.toString(d2));
  15. return b1.add(b2).doubleValue();
  16. }
  17. /**
  18. * 提供精確的減法運算。
  19. * @param v1 被減數
  20. * @param v2 減數
  21. * @return 兩個參數的差
  22. */
  23. public static double sub(double v1, double v2) {
  24. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  25. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  26. return b1.subtract(b2).doubleValue();
  27. }
  28. /**
  29. * 提供精確的乘法運算。
  30. * @param v1 被乘數
  31. * @param v2 乘數
  32. * @return 兩個參數的積
  33. */
  34. public static double mul(double v1, double v2) {
  35. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  36. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  37. return b1.multiply(b2).doubleValue();
  38. }
  39. /**
  40. * 提供(相對)精確的除法運算,當發生除不盡的情況時,精確到 小數點以后10位,以后的數字四舍五入。
  41. * @param v1 被除數
  42. * @param v2 除數
  43. * @return 兩個參數的商
  44. */
  45. public static double div(double v1, double v2) {
  46. return div(v1, v2, DEF_DIV_SCALE);
  47. }
  48. /**
  49. * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale參數指 定精度,以后的數字四舍五入。
  50. * @param v1 被除數
  51. * @param v2 除數
  52. * @param scale 表示表示需要精確到小數點以后幾位。
  53. * @return 兩個參數的商
  54. */
  55. public static double div(double v1, double v2, int scale) {
  56. if (scale < 0) {
  57. throw new IllegalArgumentException(
  58. "The scale must be a positive integer or zero");
  59. }
  60. BigDecimal b1 = new BigDecimal(Double.toString(v1));
  61. BigDecimal b2 = new BigDecimal(Double.toString(v2));
  62. return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
  63. }
  64. }
然后策略模式的核心出來了,幾種類都已經實現類,并且都有算法,策略模式要做的,就是 對這個抽象出來的 算法進行 維護,如下:
   
  1. public class PriceCalculateContext {
  2. PriceCalculate cal = null;
  3. /**無活動情況
  4. * @param sourcePrice
  5. */
  6. public PriceCalculateContext(double sourcePrice){
  7. cal = new NormalPrice(sourcePrice);
  8. }
  9. /**打折活動
  10. * @param sourcePrice 原價
  11. * @param debet 打折力度
  12. */
  13. public PriceCalculateContext(double sourcePrice,double debet){
  14. cal = new DebetPrice(sourcePrice,debet);
  15. }
  16. /**返現活動
  17. * @param sourcePrice 原價
  18. * @param conditionPrice 返現所需滿足額度
  19. * @param returnPrice 返現力度
  20. */
  21. public PriceCalculateContext(double sourcePrice,double conditionPrice,double returnPrice){
  22. cal = new ReturnPrice(sourcePrice,conditionPrice,returnPrice);
  23. }
  24. public double getResult() {
  25. return cal.getFinalPrice();
  26. }
  27. }
與之前的工廠模式相比較,策略模式并沒有提供創建運算類的工廠類,而只是將這些運算類維護在了PriceCalculateContext類中,并且此類中提供了方法getResult(),此方法所調用的剛好是算法接口。那么現在,客戶端的代碼就非常的清晰了:
   
  1. public class Start {
  2. public static void main(String[] args) {
  3. PriceCalculateContext p = new PriceCalculateContext(100d);
  4. System.out.println(p.getResult());
  5. p = new PriceCalculateContext(122.2d, 100d, 15d);
  6. System.out.println(p.getResult());
  7. }
  8. }
通過構造價格計算維護類來計算所得的最終結果,計算的具體形式完全對客戶端屏蔽。策略模式最明顯的就是對每種策略所實現的算法進行了封裝,在本例中,就是 PriceCalculateContext的getResult的方法,在后續,可以說如果需要新增新的算法,那么我只需要新增新的算法類,然后在PriceCalculateContext增加相應的映射即可。在客戶端只需要依據不同的參數進行初始化,然后調用的方法不用發生任何改變。
UML圖如下:

從類圖上也可以看到,客戶端的代碼只關聯PriceCalculateContext類,解耦很成功。

還是強調一點,策略模式注重對策略的封裝。



總結分析:
1、比較工廠模式,此模式通過增加算法維護類(PriceCalculateContext),對所有的算法進行封裝,并且在客戶端代碼中,只有此類創建和使用。
2、當新增類的時候,需要算法維護類中修改代碼,相當于需求和實現做映射關系。即客戶端代碼依然沒有轉移條件判斷。




來自為知筆記(Wiz)


轉載于:https://my.oschina.net/u/1182369/blog/406571

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

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

相關文章

Linux創建、刪除文件和文件夾命令

https://www.cnblogs.com/c-x-m/p/9794082.html轉載于:https://www.cnblogs.com/sun-ldy/p/10279025.html

Java編寫代理服務器(Burp攔截Demo)一

大家都知道大名鼎鼎的BurpSuite代理神器&#xff0c;對于抓取HTTP請求非常好用&#xff0c;偶然&#xff0c;一朋友問我Java應該如何去編寫代理服務器&#xff08;因為他想做某些東西&#xff09;&#xff0c;有沒有相關的API 去實現&#xff0c;我想說&#xff0c;差不多你能想…

mysql實戰33 | 我查這么多數據,會不會把數據庫內存打爆?

我經常會被問到這樣一個問題&#xff1a;我的主機內存只有 100G&#xff0c;現在要對一個 200G 的大表做全表掃描&#xff0c;會不會把數據庫主機的內存用光了&#xff1f;這個問題確實值得擔心&#xff0c;被系統 OOM&#xff08;out of memory&#xff09;可不是鬧著玩的。但…

[BZOJ2125]最短路

Description 給一個N個點M條邊的連通無向圖&#xff0c;滿足每條邊最多屬于一個環&#xff0c;有Q組詢問&#xff0c;每次詢問兩點之間的最短路徑。 Input 輸入的第一行包含三個整數&#xff0c;分別表示N和M和Q 下接M行&#xff0c;每行三個整數v&#xff0c;u&#xff0c;w表…

Rabbit MQ windows下安裝

Rabbit MQ 是建立在強大的Erlang OTP平臺上&#xff0c;因此安裝Rabbit MQ的前提是安裝Erlang。通過下面兩個連接可以下載安裝最新的版本&#xff1a; 下載并安裝 Eralng OTP For Windows otp_win64_18.3.exe&#xff08;erlang的環境&#xff09;運行安裝 Rabbit MQ Serve…

spark集群配置以及java操作spark小demo

spark 安裝配置使用java來操作sparkspark 安裝 tar -zxvf spark-2.4.0-bin-hadoop2.7.tgz rm spark-2.4.0-bin-hadoop2.7.tgz mv spark-2.4.0-bin-hadoop2.7 sparksudo vim /etc/profileexport SPARK_HOME/usr/local/stormexport PATH$PATH:$SPARK_HOME/binsource /etc/profile…

C++筆記(3)——string.h相關的一些小知識

strlen() 用于得到字符數組中第一個\0前的字符的個數&#xff0c;格式如下&#xff1a; strlen(數組); 例子&#xff1a; #include <stdio.h> #include <string.h>int main(){char str[10];gets(str);int len strlen(str);printf("%d\n", len);return 0…

最近發現系統rabbitmq丟消息比較嚴重,于是想了些方案來查找原因,給將消息發送方式添加確認機制。 我們在本地模擬了wms發送打標消息的場景. 1. 有事務 2. 先發點對點隊列, 再發訂

最近發現系統rabbitmq丟消息比較嚴重&#xff0c;于是想了些方案來查找原因&#xff0c;給將消息發送方式添加確認機制。 我們在本地模擬了wms發送打標消息的場景. 1. 有事務 2. 先發點對點隊列, 再發訂閱隊列 3. 批量發送 4. 在生產環境與測試環境的RabbitMQ都進行了測試 …

uoj#388. 【UNR #3】配對樹(線段樹合并)

傳送門 先考慮一個貪心&#xff0c;對于一條邊來說&#xff0c;如果當前這個序列中在它的子樹中的元素個數為奇數個&#xff0c;那么這條邊就會被一組匹配經過&#xff0c;否則就不會 考慮反證法&#xff0c;如果在這條邊兩邊的元素個數都是偶數&#xff0c;那么至少有兩組匹配…

一道Js判斷對象是否相等面試題引發的故事

話說&#xff0c;說什么呢&#xff0c;先看下題吧還是、 function checkName(data) { if (data { name: LIMING }) { console.log("one"); 復制代碼 } else if (data { name: LIMING }) { console.log(two"); 復制代碼 } else { console.log("three&quo…

序列化

什么是序列化&#xff1f;為什么要實現序列化&#xff1f;有什么作用&#xff1f; 序列化就是把具體的對象轉化成二進制的字節碼文件進行存儲或網絡傳輸。反過來就是反序列化。 將要存儲或網絡傳輸的對象必須實現序列化才可以。 如果一個類已經實現了序列…

搭建Hive平臺

http://www.cnblogs.com/gpcuster/archive/2010/02/24/1672635.html Hive是一個基于Hadoop的數據倉庫平臺。通過hive&#xff0c;我們可以方便地進行ETL的工作。hive定義了一個類似于SQL的查詢語言&#xff1a;HQL&#xff0c;能夠將用戶編寫的QL轉化為相應的Mapreduce程序基于…

Java語言與sikuli配合

很早之前寫過一篇介紹sikuli的文章。本文簡單介紹如何在java中使用sikuli進自動化測試。 圖形腳本語言sikuli sikuli IDE可以完成常見的單擊、右擊、移動到、拖動等鼠標操作&#xff0c;java引用sikuli-script.jar同樣可以執行這些常見的鼠標操作&#xff0c;因此即可方便的編寫…

列表生成式,生成器表達式,模塊的使用

三元表達式 無論條件成立與否都要返回一個值, 用于簡化僅有一個判斷的函數(或代碼塊)遞歸 遞歸有循環調用的次數限制,調用函數時,函數相關數據要入棧,而棧區是有限的 二分查找法匿名函數 僅能在定義時使用一次,定義完了就沒了 參數沒有括號,不能有return,會自…

C#怎么用代碼模擬手機去訪問手機網站抓取數據

WebClient client new WebClient ();client.Headers.Add ("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");更改user-agent為手機瀏覽器的。模擬谷歌Android&#xff1a;user-agent"Mozilla/5.0 (Linux; …

angular6 iframe應用

問題一、 iframe如何自適應屏幕高度 解決思路&#xff1a;通過設置iframe外層父元素高度等于window高度&#xff0c;再相對于父元素定位iframe元素&#xff1b;案例如下&#xff1a; 第一步: 模板文件中使用iframe // demo.component.html <div style"position: relati…

jquery下載地址:https://code.jquery.com/jquery/ 影響范圍: 版本低于1.7的jQuery過濾用戶輸入數據所使用的正則表達式存在缺陷,可能導致LOCA

jquery下載地址&#xff1a;https://code.jquery.com/jquery/ 影響范圍&#xff1a; 版本低于1.7的jQuery過濾用戶輸入數據所使用的正則表達式存在缺陷&#xff0c;可能導致LOCATION.HASH跨站漏洞 已測試成功版本&#xff1a; jquery-1.6.min.js&#xff0c;jquery-1.6.1.min…

Myeclipse常用快捷鍵

2019獨角獸企業重金招聘Python工程師標準>>> Ctrl1 快速修復 CtrlD: 刪除當前行 CtrlQ 定位到最后編輯的地方 CtrlL 定位在某行 CtrlO 快速顯示 OutLine CtrlT 快速顯示當前類的繼承結構 CtrlW 關閉當前Editer CtrlK 快速定位到下一個 CtrlE 快速顯示當前Edi…

數字三角形

問題描述 &#xff08;圖&#xff13;.&#xff11;&#xff0d;&#xff11;&#xff09;示出了一個數字三角形。 請編一個程序計算從頂至底的某處的一條路徑&#xff0c;使該路徑所經過的數字的總和最大。●每一步可沿左斜線向下或右斜線向下走&#xff1b;●1&#xff1c;三…

版本低于1.7的jQuery過濾用戶輸入數據所使用的正則表達式存在缺陷

jquery下載地址&#xff1a;https://code.jquery.com/jquery/ 影響范圍&#xff1a; 版本低于1.7的jQuery過濾用戶輸入數據所使用的正則表達式存在缺陷&#xff0c;可能導致LOCATION.HASH跨站漏洞 已測試成功版本&#xff1a; jquery-1.6.min.js&#xff0c;jquery-1.6.1.min.…