1.Strategy Pattern(策略模式)

来源:http://www.cnblogs.com/lanshanxiao/archive/2017/12/03/7878631.html
-Advertisement-
Play Games

策略模式(Strategy Pattern): 我的理解,將代碼中每個變化之處抽出,提煉成一個一個的介面或者抽象類,讓這些變化實現介面或繼承抽象類成為具體的變化類。再利用多態的功能,可將變化之處用介面或抽象類的對象代替,再用其子類為對象賦值,這樣就可以將對象隨時更換成具體的變化類。 枯燥的文字描述總 ...


策略模式(Strategy Pattern):

  我的理解,將代碼中每個變化之處抽出,提煉成一個一個的介面或者抽象類,讓這些變化實現介面或繼承抽象類成為具體的變化類。再利用多態的功能,可將變化之處用介面或抽象類的對象代替,再用其子類為對象賦值,這樣就可以將對象隨時更換成具體的變化類。

  枯燥的文字描述總是沒有實際的例子淺顯易懂。

舉例:(我是基於notepad++和cmd命令編譯運行的JAVA代碼

  現在有個鴨子俱樂部,裡面有各式各樣的鴨子(只有想不到,沒有做不到的鴨子)。

  我們來一步一步實現這個鴨子類:

  1.定義一個抽象鴨子類(Duck):

 1 public abstract class Duck{//抽象鴨子類
 2     public void fly(){//行為:飛行
 3         System.out.println("I'm flying!");
 4     }
 5     public void quack(){//行為:呱呱叫
 6         System.out.println("Gua Gua!");
 7     }
 8     public void swim(){//行為:游泳
 9         System.out.println("I'm swimming!");
10     }
11 }
Duck

  2.實現一個正常的鴨子類(GreenDuck):

1 public class GreenDuck extends Duck{//GreenDuck直接繼承Duck,什麼都不做
2     
3     public GreenDuck(){
4     }
5 }
GreenDuck

  3.測試類(DuckTest):

1 public class DuckTest{//測試類
2     public static void main(String args[]){
3         GreenDuck greenDuck = new GreenDuck();//實例化一隻GreenDuck
4         greenDuck.fly();
5         greenDuck.quack();
6         greenDuck.swim();
7     }
8 }
DuckTest

  編譯運行+結果:

  大功告成!我們去慶祝一下。

  正在慶祝,鴨子俱樂部來電話說,我們不僅只要一隻GreenDuck,還要RedDuck...不管什麼顏色的鴨子都要。你一口應承下來,沒問題只是多寫幾個繼承的類而已。

  鴨子俱樂部繼續說道,我們還要不會飛,不會叫的橡皮鴨,所有顏色的橡皮鴨來一套。你很心虛的答應了,可能今晚要加班加點了,讓各種顏色的橡皮鴨繼承Duck但是要覆蓋其中的fly和quack行為。

  鴨子俱樂部沒完沒了的繼續說道,我們還要各種顏色的鴨鳴器,它們只會叫不會飛。現在你心裡一定恨死各種顏色這個單詞了。

  鴨子俱樂部嘴停不下來說各種顏色的...

  .......

  第二天,哭暈在廁所中。

   現在,來看看到底是什麼問題導致我們要不停的重覆寫大量的代碼:各種顏色

  沒錯就是這個單詞讓我們不停地去寫各種各樣的鴨子實現類(都繼承自Duck抽象類),並且有的鴨子不會飛,有的會飛不會叫...

  現在有沒有感覺到繼承帶來的恐懼感?我們可以讓所有的同類鴨子都繼承自Duck抽象類,但是每種鴨子都有自己獨特的行為,導致我們要不停地去覆蓋Duck抽象類中的行為。

  問題找到了。就是繼承自抽象類的行為不符合每種鴨子獨特的行為導致我們不停地去手動改寫或添加行為。我們寫這麼多的重覆代碼,沒有將代碼復用,比如,有的鴨子會飛,有的鴨子會叫,有的鴨子會游泳,有的鴨子不會叫...這麼多的行為都寫在鴨子實現類中,導致代碼冗餘,沒有將它們復用。

下麵讓我們的救星:策略模式(Strategy Pattern)登場:

  1.首先,fly()和quack()兩個方法是一直在變化的,所以我們將這兩個變化之處從Duck抽象類中提煉出來變成FlyBehavior介面和QuackBehavior介面,併在Duck抽象類中定義flyBehavior和quackBehavior兩個對象。

 1 public abstract class Duck{//抽象鴨子類
 2 
 3     /*增加兩個介面對象*/
 4     FlyBehavior flyBehavior;//飛行類對象
 5     QuackBehavior quackBehavior;//呱呱叫類對象
 6     
 7     public Duck(){
 8     }
 9     
10     //去除下麵兩個方法
11     /*public void fly(){//行為:飛行
12         System.out.println("I'm flying!");
13     }
14     public void quack(){//行為:呱呱叫
15         System.out.println("Gua Gua!");
16     }*/
17     
18     /*增加下麵兩個方法,這就是將Duck類的行為委托給兩個介面對象實現*/
19     public void performFly(){//將fly()委托給flyBehavior對象實現
20         flyBehavior.fly();
21     }
22     public void performQuack(){//將quack()委托給quackBehavior對象實現
23         quackBehavior.quack();
24     }
25     
26     
27     public void swim(){//行為:游泳
28         System.out.println("I'm swimming!");
29     }
30 }
Duck
1 public interface FlyBehavior{//從Duck抽象類中抽出的fly()方法變成了FlyBehavior介面
2     public void fly();
3 }
FlyBehavior
1 public interface QuackBehavior{//從Duck抽象類中抽出的quack()方法變成了QuackBehavior介面
2     public void quack();
3 }
QuackBehavior

  其次,將變化具體類分別繼承FlyBehavior和QuackBehavior兩個介面:

  兩個飛行具體變化類:

1 public class FlyWithWings implements FlyBehavior{
2     public void fly(){
3         System.out.println("I'm flying!");
4     }
5 }
FlyWithWings
1 public class FlyNoWay implements FlyBehavior{
2     public void fly(){
3         System.out.println("I can't fly!");
4     }
5 }
FlyNoWay

  兩個呱呱叫具體變化類:

1 public class Quack implements QuackBehavior{
2     public void quack(){
3         System.out.println("Quack quack!");
4     }
5 }
Quack
1 public class MuteQuack implements QuackBehavior{
2     public void quack(){
3         System.out.println("<< Silence >>");
4     }
5 }
MuteQuack

  最後,實現一個具體類和測試類:

 1 public class GreenDuck extends Duck{//GreenDuck直接繼承Duck
 2     
 3     public GreenDuck(){
 4         flyBehavior = new FlyWithWings();
 5         quackBehavior = new Quack();
 6     }
 7     
 8     /*增加一個展示自己是什麼鴨子的方法*/
 9     public void display(){
10         System.out.println("I'm GreenDuck!");
11     }
12 }
GreenDuck
1 public class DuckTest{//測試類
2     public static void main(String args[]){
3         GreenDuck greenDuck = new GreenDuck();//實例化一隻GreenDuck
4         greenDuck.performFly();
5         greenDuck.performQuack();
6         greenDuck.swim();
7         greenDuck.display();
8     }
9 }
DuckTest

編譯運行,結果:

上面的結果,我們可以隨時隨地的實現不同的具體的鴨子類了,只要在具體的鴨子類中為flyBehavior和quackBehavior實現不同的變化類就好。

  2.動態的實現具體變化類的改變:

  在Duck類中添加兩個新方法(setFlyBehavior(Flybehavior fb)和 setQuackBehavior(QuackBehavior qb) ):

 1 public abstract class Duck{//抽象鴨子類
 2 
 3     /*增加兩個介面對象*/
 4     FlyBehavior flyBehavior;//飛行類對象
 5     QuackBehavior quackBehavior;//呱呱叫類對象
 6     
 7     public Duck(){
 8     }
 9     
10     //去除下麵兩個方法
11     /*public void fly(){//行為:飛行
12         System.out.println("I'm flying!");
13     }
14     public void quack(){//行為:呱呱叫
15         System.out.println("Gua Gua!");
16     }*/
17     
18     /*增加下麵兩個方法,這就是將Duck類的行為委托給兩個介面對象實現*/
19     public void performFly(){//將fly()委托給flyBehavior對象實現
20         flyBehavior.fly();
21     }
22     public void performQuack(){//將quack()委托給quackBehavior對象實現
23         quackBehavior.quack();
24     }
25     
26     /*添加兩個新方法,可以動態的改變具體變化類*/
27     public void setFlyBehavior(FlyBehavior fb){
28         flyBehavior = fb;
29     }
30     public void setQuackBehavior(QuackBehavior qb){
31         quackBehaior = qb;
32     }
33     
34     
35     public void swim(){//行為:游泳
36         System.out.println("I'm swimming!");
37     }
38 }
Duck

  改造測試類:

 1 public class DuckTest{//測試類
 2     public static void main(String args[]){
 3         GreenDuck greenDuck = new GreenDuck();//實例化一隻GreenDuck
 4         greenDuck.performFly();//一開始GreenDuck會飛
 5         greenDuck.performQuack();//一開始GreenDuck會叫
 6         
 7         /*動態改變greenDuck的行為*/
 8         greenDuck.setFlyBehavior(new FlyNoWay());
 9         greenDuck.setQuackBehavior(new MuteQuack());
10         
11         greenDuck.performFly();//現在不會飛了
12         greenDuck.performQuack();//現在不會叫了
13     }
14 }
DuckTest

編譯運行,結果:

代碼下載網址:

https://github.com/lanshanxiao/Head-First-Design-Pattern/tree/master/1.%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F(StrategyPattern)%E8%AE%B2%E8%A7%A3%E4%BB%A3%E7%A0%81/%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0

 

提煉一下思想:

1.封裝

2.“有一個” 比 “是一個” 好(has-a 比 is-a好)

3.多用組合少用繼承

4.封裝變化

5.正對介面編程,不針對實現編程


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 為何使用Python Python 是一種效率極高的語言。與其他眾多的語言相比,實現相同功能,使用Python編寫的程式包含的代碼更少。Python的語法簡單,易上手,使用Python編寫的代碼更容易閱讀、調試和擴展。 Python使用領域也比較多。Python應用領域有:雲計算、人工智慧、大 ...
  • 隨筆之java匿名內部類 從今天起開始每日一篇技術博客,當然這隻是我當天所學的一些隨筆,裡面或多或少會有理解不當的地方,希望大家多多指教,一起進步! 在講匿名內部類之前,先講講內部類的一些概念。 1.內部類:顧名思義,內部類就是寫在一個類裡面的類(廢話),這裡大家可能會問了,為什麼我們不直接寫一個c ...
  • 三、tornado.web.Application 1、Application:tornado.web.Aplication新建一個應用,可通過直接實例化這個類或實例化它的子類來新建應用; 2、handlers:實例化時至少需要傳入參數handlers,handlers為元素為元組的列表,元組中第一 ...
  • 周末真的是懶到心慌。。。。。。 本文是在完整s2sh項目基礎上添加的,不太瞭解s2sh項目構建的朋友可以先參考一下這幾篇文章: eclipse環境下基於tomcat-7.0.82構建struts2項目 eclipse環境下基於已構建struts2項目整合spring+hibernate 基於已構建S ...
  • 在Web開發過程中離不開數據的交互,這就需要規定交互數據的相關格式,以便數據在客戶端與伺服器之間進行傳遞。數據的格式通常有2種:1、xml;2、JSON。通常來說都是使用JSON來傳遞數據。本文正是介紹在Java中JSON與對象之間互相轉換時遇到的幾個問題以及相關的建議。 首先明確對於JSON有兩個 ...
  • File的知識 ...
  • 迭代器的方式會產生鎖定 伺服器端增加發送給每個客戶端已收到信息的功能 所以當獲取到一個socket,並打開它的線程進行迴圈接收客戶端發來信息時,我們把這個內部類的線程Client保存到集合List<Client>中 然後在讀取到客戶端信息後,把這個信息發送給所有埠 通過迴圈 for(int i=0 ...
  • import random help(random) FUNCTIONS betavariate(alpha, beta) method of Random instance # 隨機實例的方法 Beta distribution. # β分佈 Conditions on the parameter... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...