摘要:下面我們就來介紹怎么用策略模式來解決這個問題。結果很快的跳很快的跑紅藍相間的超人狗不會跳不會跑紅藍相間的超人狗總結策略模式就是把所有的可變的行為都抽取出來放到接口中,然后定義很多的行為類去實現接口。
策略模式就是定義了一系列的的算法,將它們都多帶帶封裝起來,讓他們之間可以相互替換,可以讓算法的變化獨立于使用算法的客戶。
首先創建一個Dog父類,有run方法控制跑,jump方法控制跳,color方法控制顏色。
public class Dog { public void run(){ System.out.println("狗在跑"); } public void jump(){ System.out.println("狗在跳"); } public void color(){ } }
創建兩個子類,分別是WhiteDog和BlackDog,都重寫了父類的color方法,運行一下。
public class WhiteDog extends Dog { @Override public void color() { System.out.println("白顏色的狗"); } } public class BlackDog extends Dog { @Override public void color() { System.out.println("黑顏色的狗"); } } public class Test { public static void main(String[] args){ WhiteDog whiteDog = new WhiteDog(); whiteDog.run(); whiteDog.jump(); whiteDog.color(); BlackDog blackDog = new BlackDog(); blackDog.run(); blackDog.jump(); blackDog.color(); } }
結果:
狗在跑
狗在跳
白顏色的狗
狗在跑
狗在跳
黑顏色的狗
這個時候看上去好像很完美沒有任何問題,但是有一天我們又新建了一個公仔狗的對象Doll dog,這個時候我們發現好像有點不對,公仔狗是不會跳也不會跑的。可以如果繼承了Dog父類他就自帶跑和跳的功能了,那就不對了。
public class DollDog extends Dog {
@Override public void color() { System.out.println("五顏六色"); }
}
DollDog dollDog = new DollDog(); dollDog.run(); dollDog.jump(); dollDog.color();
結果:
狗在跑
狗在跳
五顏六色的玩具狗
這個時候我們靈機一動想到可以讓子類覆蓋父類run方法和jump方法,讓DollDog中的跑和跳功能失效,我們再運行一下。
@Override public void run() { System.out.println("玩具狗不會跑"); } @Override public void jump() { System.out.println("玩具狗不會跳"); }
結果:
玩具狗不會跑
玩具狗不會跳
五顏六色的玩具狗
看起來是解決了問題,但是如果一天要增加100個各種各樣的狗的話難道我們要讓100個新建的子類都重寫父類的方法嗎?這個時候父類里面還只有3個方法,如果是30個呢?如果我們都靠子類重寫的話那效率該多低呢?有沒有別的方法來解決呢?答案是肯定的。下面我們就來介紹怎么用策略模式來解決這個問題。
首先我們要知道設計模式中第一個原則,要把代碼中經常需要修改的部分獨立抽取出來,不要和其他代碼混在一起,這樣更便于我們擴展要修改的部分 。目前來看最常變化的是run和jump方法。所以我們可以將這兩個方法抽取出來,這里就要說到設計模式中第二個原則,針對接口編程,而不是現實編程。比如run和jump有不同的種類,我們可以聲明一個接口里面定義run和jump方法,然后創建許多類去實現,調用的時候動態選擇類型。這種類被稱為行為類。行為類中的代碼可以進行復用,卻不會有繼承帶來的那些麻煩。
定義方法的接口:
public interface RunBehavior { void run(); } public interface JumpBehavior { void jump(); }
實現方法的行為類:
public class RunNoWay implements RunBehavior { @Override public void run() { System.out.println("不會跑"); } } public class RunFast implements RunBehavior { @Override public void run() { System.out.println("很快的跑"); } } public class RunSlow implements RunBehavior { @Override public void run() { System.out.println("很慢的跑"); } } public class JumpNoWay implements JumpBehavior { @Override public void jump() { System.out.println("不會跳"); } } public class JumpFast implements JumpBehavior { @Override public void jump() { System.out.println("很快的跳"); } }
現在我們將變化的部分抽取出來了,所以Dog父類就會把run和jump的操作委托給行為類處理,那么具體要怎么使用這些行為類?這里就需要在Dog父類中定義兩個實例變量,聲明類型為RunBehavior和JumpBehavior,所以在代碼運行的時候會用多態的方式引用正確的類型。然后在父類中的run和jump方法中委托行為類去執行功能。
public class Dog { public RunBehavior runBehavior; public JumpBehavior jumpBehavior; public void run(){ runBehavior.run(); } public void jump(){ jumpBehavior.jump(); } public void color(){ } }
最后當我們沒出現一個新的類型的狗狗的時候,我們為它創建一個新類然后繼承Dog父類,然后我們在子類的構造方法中獲取父類中兩個接口的引用,根據自己的需要通過多態指定不同的行為類。
public class SuperDog extends Dog { public SuperDog(){ runBehavior = new RunFast(); jumpBehavior = new JumpFast(); } @Override public void color() { System.out.println("紅藍相間的超人狗"); } } Dog dog = new SuperDog(); dog.jump(); dog.run(); dog.color();
結果:
很快的跳
很快的跑
紅藍相間的超人狗
最后我們還有一個小問題,每次指定選擇類的時候都是在子類的構造方法中指定,可不可以動態的指定呢?當然可以,我們只需要為聲明的接口引用添加兩個set方法。然后在外部調用即可。
public void setRunBehavior(RunBehavior runBehavior) { this.runBehavior = runBehavior; } public void setJumpBehavior(JumpBehavior jumpBehavior) { this.jumpBehavior = jumpBehavior; } Dog dog = new SuperDog(); dog.jump(); dog.run(); dog.color(); dog.setJumpBehavior(new JumpNoWay()); dog.setRunBehavior(new RunNoWay()); dog.jump(); dog.run(); dog.color();
結果:
很快的跳
很快的跑
紅藍相間的超人狗
不會跳
不會跑
紅藍相間的超人狗
總結:
策略模式就是把所有的可變的行為都抽取出來放到接口中,然后定義很多的行為類去實現接口。在父類中聲明了接口的引用利用多態去動態的選擇自己需要的行為類,避免了以前因為單純的繼承造成的每次的新變動都需要寫大量的重復代碼,而現在只需要定義好行為類進行復用即可,不需要修改原本的代碼。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/69045.html
摘要:基礎問題的的性能及原理之區別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調機制解讀抽象類與三大特征時間和時間戳的相互轉換為什么要使用內部類對象鎖和類鎖的區別,,優缺點及比較提高篇八詳解內部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區別詳解-備忘筆記 深入理解Java Stream流水...
摘要:基礎問題的的性能及原理之區別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調機制解讀抽象類與三大特征時間和時間戳的相互轉換為什么要使用內部類對象鎖和類鎖的區別,,優缺點及比較提高篇八詳解內部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區別詳解-備忘筆記 深入理解Java Stream流水...
摘要:基礎問題的的性能及原理之區別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調機制解讀抽象類與三大特征時間和時間戳的相互轉換為什么要使用內部類對象鎖和類鎖的區別,,優缺點及比較提高篇八詳解內部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區別詳解-備忘筆記 深入理解Java Stream流水...
摘要:當活動線程核心線程非核心線程達到這個數值后,后續任務將會根據來進行拒絕策略處理。線程池工作原則當線程池中線程數量小于則創建線程,并處理請求。當線程池中的數量等于最大線程數時默默丟棄不能執行的新加任務,不報任何異常。 spring-cache使用記錄 spring-cache的使用記錄,坑點記錄以及采用的解決方案 深入分析 java 線程池的實現原理 在這篇文章中,作者有條不紊的將 ja...
閱讀 1030·2023-04-25 22:27
閱讀 877·2021-11-22 14:56
閱讀 992·2021-11-11 16:54
閱讀 1687·2019-08-30 15:54
閱讀 3508·2019-08-30 13:20
閱讀 1219·2019-08-30 10:55
閱讀 2087·2019-08-26 13:34
閱讀 3286·2019-08-26 11:53