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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...