摘要:不會叫鴨子呱呱呱叫。。。。。。此時我剛剛寫的例子基于一個策略模式思想寫的。感謝你看到這里,策略模式部分結束,本人文筆隨便,若有不足或錯誤之處望給予指點,度彎腰很快我會發布下一個設計模式內容,生命不息,編程不止參考書籍設計模式
并不是每個自稱自己是個OO的人,他就一定能運用好OOP。
普通程序員寫的東西好比一把普通鑰匙,一把鑰匙只能開一個門,而高級程序員就會“造”萬能鑰匙。
我以前所理解的“簡單”就是一把鑰匙開一把鎖的模式,僅僅只是著眼于解決現在的問題,而設計模式的“復雜”在于它需要造出具有“通用性”的萬能鑰匙。而我以前寫的代碼就是前者,這個“簡單”不是功能的簡單,而是設計的簡單。簡單的設計意味著缺少靈活性,代碼很鋼硬,僅僅只是面向過程,一步操作緊挨著下一步。
要使代碼可被反復使用,請用’設計模式’對你的代碼進行設計.
模擬鴨子程序開始了。
首先來一張類圖,這是鴨子程序原始狀態
而此時我們需要添加一個新功能:鴨子飛功能(吐槽:明明很多鴨子不會飛)
這很簡單,難不倒我們“有OO思想”的人
但這樣的設計運用在下面拓展的程序上會變成什么呢?
哇哦,很明顯橡皮鴨子不能飛,而在此設計中使用繼承(extends)就變得不合理了,
但是我們可以投機取巧一點,變成如下圖
這樣小聰明的方法,恐怕我自己看的都不能直視了....
很明顯對于繼承在這個設計當中很幾個致命的地方
1:各個鴨子子類繼承父類時,使得代碼在多個子類中重復
2:沒有拓展性,對于改變會費勁
3:往往改變一點地方很多地方就都要跟著改變,找出其他鴨子類中不想要的改變,牽一發而動全身。
設計原則一:找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起
注:當每次有新的需求的時候,就會使某方面發生變化,那么你就可以確定,這部分的代碼就需要被抽出來,和其他穩定的代碼有所區分,這樣使得代碼變化引起的不經意后果變少,系統變得更加富有彈性。
設計原則二:針對接口編程,而不是針對實現編程。
注:從現在開始我們編寫的代碼要富有彈性,讓其運行時能“動態”的改變飛行或者呱呱叫行為
進行一點小改變
這里將飛行和叫的行為各自“抽象”出來成接口,這兩個行為被分開成兩個類,這兩個類專門為提供某行為的實現提供接口。不同與之前設計:行為來自Duck父類中子類的具體實現,或是繼承某個接口并由子類自行實現而來。這兩種做法都依賴“實現”。而此時子類將使用接口所代表的行為,所以實際的“實現”不會被綁死在鴨子的子類中。(特定的具體行為編寫在實現了FlyBehavior和QuackBehavior接口的實現類中)
這里放出具體行為設計
注:此時飛行和叫的動作(接口)可以被其他對象復用,此時這兩個行為和鴨子類(Duck)無關了,而且往后加入新的行為也不怕了大量修改代碼了。
鴨子父類:
package Entity; import Interface.FlyBehavior; import Interface.QuackBehavior; //鴨子父類 public class Duck { // 添加兩個接口變量 FlyBehavior flyBehavior;// 每只鴨子都會引用完成FlyBehavior接口的對象 QuackBehavior quackBehavior;// 每只鴨子都會引用完成QuackBehavior接口的對象 public FlyBehavior getFlyBehavior() { return flyBehavior; } public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public QuackBehavior getQuackBehavior() { return quackBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } public Duck() { } public void swim() { System.out.println("鴨子游泳。。。。。。"); } // 動作 public void display() { System.out.println("每只鴨子都會動"); } // 這些方法取代fly(),quack() // 鴨子對象不親自處理呱呱呱叫行為,而是委托給quackBehavior引用對象 public void performQuack() { quackBehavior.quack(); } // 鴨子對象不親自處理飛行為,而是委托給flyBehavior引用對象 public void performFly() { flyBehavior.fly(); }; }
飛行和叫動作接口
package Interface; //飛行接口 public interface FlyBehavior { public void fly(); }
package Interface; //鴨子叫接口 public interface QuackBehavior { public void quack(); }
//綠頭鴨和橡皮鴨類
package Entity; import Implements.FlyWithWings; import Implements.Quack; //綠頭鴨子類 public class MallardDuck extends Duck { @Override public void display() { System.out.println("綠頭鴨子"); } /* 當MallardDuck被實例化時, * 構造器會把繼承來的quackBehavior,flyBehavior * 實例變量初始化成Quack,FlyWithWings的類型 * Quack,FlyWithWings分別是接口的實現類 * */ public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } }
package Entity; import Implements.FlyNoWay; import Implements.Squeak; public class RubberDuck extends Duck { //橡皮鴨類 @Override public void display() { System.out.println("我是一只橡皮鴨"); } public RubberDuck() { quackBehavior = new Squeak(); flyBehavior = new FlyNoWay(); } }
各個行為的具體實現類,都實現了接口
package Implements; import Interface.FlyBehavior; public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("不會飛"); } }
package Implements; import Interface.FlyBehavior; public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("鴨子飛起來了。。。。。。"); } }
package Implements; import Interface.QuackBehavior; public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("不會叫"); } }
package Implements; import Interface.QuackBehavior; public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("鴨子呱呱呱叫。。。。。。"); } }
package Implements; import Interface.QuackBehavior; public class Squeak implements QuackBehavior { @Override public void quack() { System.out.println("鴨子吱吱吱叫。。。。。。"); } }
測試類
package TestMain; import Entity.Duck; import Entity.MallardDuck; import Entity.RubberDuck; public class TestMain { public static void main(String[] args) { //這里使用多態,讓Duck知道我們要創建一只綠頭鴨 Duck d = new MallardDuck(); //重載方法 d.display(); d.performQuack(); d.performFly(); System.out.print(" "); Duck a=new RubberDuck(); a.display(); a.performQuack(); a.performFly(); } }
效果:
設計原則三:多用組合,少用繼承。
注:使用組合建立系統具有很大的彈性,不僅可將算法封裝成類,更可以“動態的改變行為”,只要組合對象符合正確的接口標準即可。
此時我剛剛寫的例子基于一個策略模式思想寫的。當然你可能會問:“用這個設計模式到底有什么用呢?這樣功能我也能實現了,干嘛要搞的那么復雜?”。對此我不能用專業的思想去回答這樣的疑問,我只能說隨著自己學習的不斷深入往往很多以前自認為對的東西,其實是不正確的。
策略模式要點:
1:良好的OO設計必須具備可復用性、可擴充性、可維護性三個特征
2:模式不是代碼,而是針對設計問題的通用解決方案。
3:大多數的模式都允許系統局部改變獨立于其他部分。
4:記著把系統中會改變的部分抽出來封裝
5:模式會讓開發人員之間有共同的語言,而且會讓自己少走很多坑
這里我想說一點,很多人都覺得設計模式跟算法一樣都是可有可無的東西,我覺得用設計模式是著眼于未來,可以提高系統的擴展性,減少重復勞動,雖然有的時候可能會增加工作量,但比起后期無止境的維護,這點反而不算什么,而設計模式是不會提高系統運行速度的,但我認為設計模式非常重要,包括帶我的前輩程序員都教導我腦中要有模式概念,當然這個要因人而異。
感謝你看到這里,策略模式部分結束,本人文筆隨便,若有不足或錯誤之處望給予指點,90度彎腰~很快我會發布下一個設計模式內容,生命不息,編程不止!
參考書籍:《Head First 設計模式》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67596.html
摘要:本篇主要講述中使用函數來實現策略模式和命令模式,最后總結出這種做法背后的思想。 《流暢的Python》筆記。本篇主要講述Python中使用函數來實現策略模式和命令模式,最后總結出這種做法背后的思想。 1. 重構策略模式 策略模式如果用面向對象的思想來簡單解釋的話,其實就是多態。父類指向子類,根據子類對同一方法的不同重寫,得到不同結果。 1.1 經典的策略模式 下圖是經典的策略模式的U...
摘要:設計模式的定義在面向對象軟件設計過程中針對特定問題的簡潔而優雅的解決方案。從前由于使用的局限性,和做的應用相對簡單,不被重視,就更談不上設計模式的問題。 ‘從大處著眼,從小處著手’,以前對這句話一知半解,自從踏出校門走入社會,開始工作以來,有了越來越深的理解,偶有發現這句話用在程序開發中也有用,所以,近段時間開始嘗試著分析jQuery源碼,分析angularjs源碼,學習設計模式。 設...
摘要:下圖就是第一版當時的樣子年圍繞他們的發起了積極的營銷策略,比如像前文提到的那兩次小花招,借此向人們進一步傳遞了的主張。從年到年,的銷售效率指數始終大于,這說明公司在銷售與營銷上的花的每一美元都至少會收回一美元或更多的回報。 讓我們回到17年前,那天軟件服務商Siebel正在進行其用戶會議??雌饋硪磺卸际前舶察o靜的,但是加州從來就不會一直這么安靜,因為這里有好萊塢也有硅谷。突然間,Siebel...
摘要:下圖就是第一版當時的樣子年圍繞他們的發起了積極的營銷策略,比如像前文提到的那兩次小花招,借此向人們進一步傳遞了的主張。從年到年,的銷售效率指數始終大于,這說明公司在銷售與營銷上的花的每一美元都至少會收回一美元或更多的回報。 讓我們回到17年前,那天軟件服務商Siebel正在進行其用戶會議??雌饋硪磺卸际前舶察o...
摘要:繼續我們的設計模式學習,有個好的觀察者可以讓你開發效率大大提高直接進入正題,我們用一個氣象站程序來模擬此模式。內置了觀察者模式的實現。 繼續我們的設計模式學習,有個好的觀察者可以讓你開發效率大大提高 直接進入正題,我們用一個氣象站程序來模擬此模式。有一個氣象站程序,能對濕度,溫度,氣壓進行監測并顯示在顯示裝置上面模擬圖如下,此系統中有三個部分氣象站:獲取實際氣象數據的裝置Weather...
閱讀 2112·2021-11-05 09:42
閱讀 2856·2021-09-23 11:21
閱讀 2849·2019-08-30 14:00
閱讀 3318·2019-08-30 13:15
閱讀 467·2019-08-29 17:18
閱讀 3556·2019-08-29 16:29
閱讀 2754·2019-08-29 14:06
閱讀 2799·2019-08-23 14:41