1、繼承帶來的擴(kuò)展和復(fù)用問題

          繼承作為面向?qū)ο蟮娜笠?封裝、繼承、多態(tài))之一為什么會(huì)帶來問題,問題如何解決然后形成一種設(shè)計(jì)模式,head
          frist設(shè)計(jì)模式書中以鴨子作為例子講解什么情況下繼承的方式會(huì)帶來問題。首先有各種各樣的鴨子,那么自然想到各種鴨子繼承自一個(gè)父類:父類為Duck,現(xiàn)有綠頭鴨GreenHeadDuck和紅頭鴨RedHeadDuck
          public abstract Class Duck{   public void quack(){}   public void swin(){}
            public abstract void display(); } publci class GreenHeadDuck:Duck{ public
          overrid void display(){ //外觀綠頭 } } publci class ReadHeadDuck:Duck{ public
          overrid void display(){ //外觀紅頭 } }

          父類中所有鴨子都會(huì)呱呱叫(quack)和游泳(swin),外觀卻不一樣所以display為抽象方法,讓繼承它的子類重寫?,F(xiàn)在需要新增一種鴨子,但這個(gè)鴨子是一個(gè)玩具橡皮鴨,我們按照繼承的方式則橡皮鴨實(shí)現(xiàn)代碼如下
          publci class RubberDuck:Duck{  public override void qucak(){     //覆蓋成吱吱吱叫   }
          public override void display(){ //外觀是橡皮鴨 } }
            


          因?yàn)橄鹌喪遣粫?huì)像其他鴨子那樣叫的,所以上面代碼我們需要重寫qucak覆蓋橡皮鴨叫的方式可。現(xiàn)在有一個(gè)需求,需要讓鴨子飛起來,按照繼承的方式我們給父類Duck添加
          fly方法即可讓所有鴨子飛起來。但是問題出現(xiàn)了,橡皮鴨是不會(huì)飛的,于是我們可以像覆蓋qucak方法一樣在RubberDuck中覆蓋fly方法。
          public abstract class Duck{   public void quack(){}   public void swin(){}
            public abstract void display(); public void fly(){} } publci class
          RubberDuck:Duck{   public override void qucak(){     //覆蓋成吱吱吱叫   } public
          override void display(){ //外觀是橡皮鴨 } public override void fly(){ //覆蓋,什么都不做 } }
          到這里我們已經(jīng)發(fā)現(xiàn)了繼承帶來的問題:

          1、代碼在多個(gè)子類中重復(fù)。

          2、很難知道所有子類的行為。

          3、運(yùn)行的子類行為不容易改變。

          4、改變會(huì)牽一發(fā)動(dòng)全身,引起其他子類不想要的改變。

          每當(dāng)有新的子類出現(xiàn),就要檢查是不是需要覆蓋父類方法。比如再加一種木頭玩具的鴨子
          (DecoyDuck),那么木頭鴨子不會(huì)叫也不會(huì)飛,我們是不是需要覆蓋叫和飛的方法。

          2、進(jìn)一步的改進(jìn),利用接口

            由于quack和fly有可能變化,所以我們將quack 和fly抽象成接口,能夠叫和飛行的鴨子才按需求繼承接口自己實(shí)現(xiàn)方法。



          利用接口可以解決一部分問題(不在需要重寫不需要的方法
          ),但是卻會(huì)造成代碼無法復(fù)用,因?yàn)榻涌诓痪哂袑?shí)現(xiàn),我們要在每種子類中寫fly和quack。比如要在紅頭綠頭中寫"呱呱叫",要在橡皮鴨中寫"吱吱叫"。

          3、進(jìn)一步改進(jìn),策略模式

          經(jīng)過上面的分析可以引出設(shè)計(jì)模式的兩個(gè)原則

          1、把會(huì)變化的部分封裝起來,讓其他部分不會(huì)受到影響。

          2、針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)。


          通過第一個(gè)設(shè)計(jì)原則我們可以取出易于變化的部分:鴨子的飛行行為(fly)和呱呱叫的行為(quack)。通過第二個(gè)設(shè)計(jì)原則我們知道需要利用接口代表每個(gè)行為,比如FlyBehavior與QuackBehavior,而行為的每個(gè)實(shí)現(xiàn)都將實(shí)現(xiàn)其中的一個(gè)接口。這樣鴨子類就不會(huì)負(fù)責(zé)實(shí)現(xiàn)FlyBehavior與QuackBehavior,而是由行為類來專門實(shí)現(xiàn),不會(huì)綁死在鴨子的子類中。




          而"針對(duì)接口編程"的意思是"針對(duì)超類型編程"??梢悦鞔_地說明變量的聲明類型應(yīng)該是超類,這意味著我們?cè)贒uck父類中聲明的行為變量為?FlyBehavior,QuackBehavior,"針對(duì)接口編程"的關(guān)鍵就在于面向?qū)ο笕刂坏?quot;多態(tài)",由于多態(tài)我們才能在調(diào)用超類的方法時(shí)執(zhí)行的是實(shí)現(xiàn)類或子類的方法。所以我們改造之前寫的Duck類,刪除Fly()和Quack(),加入FlyBehavior和QuackBehavior變量,并用另外兩個(gè)方法PerFormFly()和PerFormQuack()來執(zhí)行兩個(gè)行為。
          public abstract Class Duck{ protected FlyBehavior flyBehavior; protected
          QuackBehavior quackBehavior;   public void swin(){}   public abstract void
          display(); public void PerFormFly(){ flyBehavior.fly(); }   public void
          PerFormQuack(){ quackBehavior.quack(); } }
          編寫相關(guān)類并測(cè)試:
          1 //封裝飛行行為 2 public interface FlyBehavior 3 { 4 public void fly(); 5 }
          6 7 public class FlyWithWings : FlyBehavior 8 { 9 public void fly() 10 {
          11 Console.WriteLine("用翅膀飛"); 12 } 13 } 14 public class FlyNoWay :
          FlyBehavior 15 { 16 public void fly() 17 { 18 Console.WriteLine("不飛,什么也不做"
          ); 19 } 20 } 21 22 //封裝叫聲行為 23 public interface QuackBehavior 24 { 25
          public void quack(); 26 } 27 28 public class Quack : QuackBehavior 29 {
          30 public void quack() 31 { 32 Console.WriteLine("呱呱叫"); 33 } 34 } 35
          public class Squack : QuackBehavior 36 { 37 public void quack() 38 { 39
          Console.WriteLine("吱吱叫"); 40 } 41 } 42 public class MuteQuack :
          QuackBehavior 43 { 44 public void quack() 45 { 46 Console.WriteLine("不會(huì)叫");
          47 } 48 } 49 50 /// <summary> 51 /// 鴨子超類 52 /// </summary> 53 public
          abstract class Duck { 54 55 protected FlyBehavior flyBehavior; 56 protected
          QuackBehavior quackBehavior; 57 58 public void swin() { } 59 public abstract
          void display(); 60 public void PerFormFly() 61 { 62 flyBehavior.fly(); 63
          } 64 public void PerFormQuack() 65 { 66 quackBehavior.quack(); 67 } 68
          } 69 70 /// <summary> 71 /// 綠頭鴨 72 /// </summary> 73 public class
          GreenHeadDuck : Duck 74 { 75 public GreenHeadDuck() { 76 flyBehavior = new
          FlyWithWings(); 77 quackBehavior = new Quack(); 78 } 79 public override void
          display() 80 { 81 Console.WriteLine("綠頭鴨,我的頭頂有一片草原(*^_^*)"); 82 } 83 } 84
          85 /// <summary> 86 /// 橡皮鴨 87 /// </summary> 88 public class RubberDuck :
          Duck 89 { 90 public RubberDuck() 91 { 92 flyBehavior = new FlyNoWay(); 93
          quackBehavior =new Squack(); 94 } 95 public override void display() 96 {
          97 Console.WriteLine("橡皮鴨"); 98 } 99 } 100 101 static void Main(string[]
          args)102 { 103 //綠頭鴨 104 Duck greenHeadDuck = new GreenHeadDuck(); 105
          greenHeadDuck.display();106 greenHeadDuck.PerFormQuack(); 107
          greenHeadDuck.PerFormFly();108 Console.WriteLine("--------------------------");
          109 //橡皮鴨 110 Duck rubberDuck = new RubberDuck(); 111 rubberDuck.display(); 112
          rubberDuck.PerFormQuack();113 rubberDuck.PerFormFly(); 114 Console.ReadKey();
          115 }



          如上測(cè)試我們?cè)邙喿幼宇愔型ㄟ^構(gòu)造方法實(shí)例化行為類,但建立了一堆動(dòng)態(tài)的功能沒有用到,是否可以動(dòng)態(tài)的設(shè)定行為而不是在構(gòu)造函數(shù)里面實(shí)例化。所以我們還可以加入兩個(gè)設(shè)置行為的方法
          SetFlyBehavior和SetQuackBehavior,再次測(cè)試動(dòng)態(tài)設(shè)定行為。
          /// <summary> /// 鴨子超類 /// </summary> public abstract class Duck { protected
          FlyBehavior flyBehavior; protected QuackBehavior quackBehavior; public void
          swin() { } public abstract void display(); public void
          SetFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; }
          public void SetQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior
          = quackBehavior; } public void PerFormFly() { flyBehavior.fly(); } public void
          PerFormQuack() { quackBehavior.quack(); } }
            

          4、策略模式 類圖總結(jié)

          策略模式:定義了算法簇,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨(dú)立于使用算法的客戶

          ?通過這張類圖可以便于理解和記憶設(shè)計(jì)模式,后續(xù)會(huì)把其他模式也分享出自己的學(xué)習(xí)和理解。


          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                天天日天天射天天舔 | 亚洲激情二区 | 亚洲不卡中文字幕 | 又黄又爽免费视频 | 操逼中国逼 |