<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      橋接模式(Bridge)

      1.1.1 摘要

           在軟件系統(tǒng)中,某些類型由于自身的邏輯,它具有兩個(gè)或兩個(gè)以上的維度變化,那么如何應(yīng)對(duì)這種“多維度的變化”呢?如何利用面向?qū)ο蟮募夹g(shù)來(lái)使得該類型能夠輕松的沿著多個(gè)方向進(jìn)行變化,而又不引入額外的復(fù)雜度呢?這就是即將要介紹的橋接模式(Bridge)。

       

      使用頻率: clip_image001  medium

       

      • 定義

              橋接模式(Bridge),將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。

      • 意圖

              將抽象與實(shí)現(xiàn)解耦。

      • 動(dòng)機(jī)

              當(dāng)一種抽象類型可能有多種實(shí)現(xiàn)方式時(shí),一般情況我們可以考慮使用繼承來(lái)解決抽象類型的多種實(shí)現(xiàn),在抽象類型中定義接口,而子類負(fù)責(zé)接口的具體實(shí)現(xiàn)。但這種做法缺乏靈活性,由于抽象類型和子類之間緊緊地綁定在一起,使得這種關(guān)系在運(yùn)行時(shí)不能再修改,這使得它難以修改、擴(kuò)展和重用不利于抽象和實(shí)現(xiàn)解耦,而且這也違背OOP原則:“優(yōu)先使用對(duì)象聚集,而不是繼承”。

      • 結(jié)構(gòu)圖

       

      clip_image001[4]

      圖1 橋接模式(Bridge)

       

      • 參與者

              Abstraction

              1. 定義抽象接口。

              2. 擁有一個(gè)Implementor類型對(duì)象引用。

       

      • RefinedAbstraction

              1. 擴(kuò)展Abstraction中的接口定義。

       

      • Implementor

              1. Implementor是具體實(shí)現(xiàn)的接口,Implementor和Abstraction接口并不一定完全一致(注:Proxy和ISubject接口一一對(duì)應(yīng)),實(shí)際上這兩個(gè)接口可以完全不一樣,Implementor提供具體操作方法,而Abstraction提供更高層次的調(diào)用。

       

      • ConcreteImplementor

              1. 實(shí)現(xiàn)Implementor接口,給出具體實(shí)現(xiàn)。

       

       

      1.1.2 正文

            首先根據(jù)橋接模式(Bridge)的定義:將抽象部分與它的實(shí)現(xiàn)部分分離,但令我不解的是,怎樣才能將抽象與其實(shí)現(xiàn)的具體方式分離呢?其實(shí)我的迷惑主要是因?yàn)檎`解了實(shí)現(xiàn)的含義。這里實(shí)現(xiàn)指的是抽象類及其派生類用來(lái)實(shí)現(xiàn)自定的對(duì)象(而不是抽象類的派生類,這些派生類被稱為具體類)。不過(guò)這樣還是難以理解,現(xiàn)在讓我們通過(guò)具體的例子說(shuō)明。

            我們必需了解橋接模式(Bridge)存在的價(jià)值,然后推遲該模式,OK我們通過(guò)一個(gè)簡(jiǎn)單的例子說(shuō)明為什么需要橋接模式(Bridge)吧!

            從一個(gè)繪制形狀的簡(jiǎn)單問(wèn)題開(kāi)始,假設(shè)我們接受一個(gè)任務(wù):編寫(xiě)一個(gè)程序,使用兩個(gè)繪圖程序DrawProgram1和DrawProgram2之一繪制圖形(矩形,圓形等),而且我們被告知,實(shí)例化圖形的時(shí)候,它會(huì)知道應(yīng)該使用繪圖程序DP1還是DP2。

           通過(guò)分析我們可以找出抽象類Shape,然后定義Retangle和Circle類繼承抽象類Shape,還有就是繪圖程序DP1和DP2。

       

      bridge1

      圖2繪圖程序類圖

       

            我們現(xiàn)在初步定義了相關(guān)的方法和類,而把Shape,Retangle和Circle都定義為抽象類型方便以后擴(kuò)展。但我們可以發(fā)現(xiàn)圖形類型并沒(méi)有與繪圖程序關(guān)聯(lián)起來(lái),而且前面需求中提到圖形實(shí)例化時(shí)候知道具體調(diào)用哪個(gè)繪圖程序。OK那么現(xiàn)在讓我們把圖形和繪圖程序關(guān)聯(lián)起來(lái)。

       

       

       bridge2

      圖3繪圖程序類圖

       

            我們定義了Retangle1和Retangle2繼承于抽象類Retangle,添加DrawLine()方法分別調(diào)用DP1和DP2的DrawLine()方法,并且Circle1和Circle2中的實(shí)現(xiàn)基本相同。我們使用了一種直截了當(dāng)?shù)姆椒?,?shí)現(xiàn)了兩種圖形和兩個(gè)繪圖程序的關(guān)聯(lián)。

            現(xiàn)在Shape有四個(gè)具體類型(Retangle1,Retangle2,Circle1和Circle2),而且每個(gè)具體類型都和相應(yīng)繪圖程序?qū)τ?,但我們要記住“沒(méi)有不變的需求,世上的軟件都改動(dòng)過(guò)三次以上,唯一一個(gè)只改動(dòng)過(guò)兩次的軟件的擁有者已經(jīng)死了,死在去修改需求的路上”,所以需求總是在不斷的變化之中,如果添加新的繪圖程序DP3,那么我們就要增加兩個(gè)具體類型,而且具體類型中調(diào)用DP3方法跟之前調(diào)用DP1、DP2并沒(méi)有太大的區(qū)別(冗余問(wèn)題),現(xiàn)在有兩種圖形(Retangle和Cirle)和三個(gè)繪圖程序(DP1,DP2和DP3),那么就擁有六種不同Shape(2種圖形 * 3個(gè)繪圖程序),如果我們繼續(xù)擴(kuò)展成三種圖形那么就具有九種不同Shape(3種圖形 * 3個(gè)繪圖程序),這就會(huì)導(dǎo)致“類爆炸”問(wèn)題。

            上面的解決方法,因?yàn)槌橄箢愋停⊿hape)和繪圖程序之間是緊耦合,于是存在嚴(yán)重的“類爆炸”問(wèn)題(每種形狀都必須知道自己用哪個(gè)繪圖程序)。我們需要一種方式將抽象上的變化和實(shí)現(xiàn)變化進(jìn)行解耦。

            將抽象與實(shí)現(xiàn)解耦這不就是橋接模式(Bridge)的意圖嗎?在介紹橋接模式(Bridge)之前,我們總結(jié)一下前面方式中的問(wèn)題。

       

      • 存在冗余
      • 低內(nèi)聚
      • 緊耦合

            由于前面的例子按照不同圖形來(lái)進(jìn)行繼承的分類,如果我們按照不同繪圖程序分類結(jié)果又如何呢?OK,那么讓我們畫(huà)出按照不同繪圖程序分類類圖。

       

      bridge3

      圖4繪圖程序類圖

       

            現(xiàn)在我們繼續(xù)使用四個(gè)類表示現(xiàn)有的圖形的組合,但這里我們按照不同繪圖程序派生不同圖形,所以我們消除了圖形類(Retangle1,Retangle2, Circle1和Circle2)和繪圖程序的之間的緊耦合,從而消除了它們之間的冗余?,F(xiàn)在把耦合轉(zhuǎn)移到更高的繼承層次,但問(wèn)題有出現(xiàn)了當(dāng)有新的繪圖程序加入時(shí),我們的確可以輕松地進(jìn)行擴(kuò)展,只要增加ShapeDP3類繼承抽象類Shape就OK了,但是要實(shí)現(xiàn)一套一模一樣的Retangle3和Circle3了。

            盡管這種方式對(duì)前面的方式有所改進(jìn),但冗余和耦合問(wèn)題依然存在。

            在我們每次使用設(shè)計(jì)模式時(shí),我們應(yīng)該根據(jù)設(shè)計(jì)原則去設(shè)計(jì),而不是直接使用已有設(shè)計(jì)模式去套用,我們要明白的一點(diǎn)是設(shè)計(jì)模式是根據(jù)一定的設(shè)計(jì)原則而產(chǎn)生的。

            這次我們要遵循兩個(gè)基本原則:

      • 找出變化封裝之
      • 優(yōu)先使用對(duì)象聚集,而不是繼承

           首先我們可以很快的找出需求中變化:圖形和繪圖程序,然后我們使用抽象來(lái)封裝變化就OK了。

       

       bridge6

      圖5封裝繪圖程序中變化

       

           現(xiàn)在我們已經(jīng)找出了變化圖形和繪圖程序,注意這里的OperationalDP1和OperationalDP2作為調(diào)用繪圖程序(DP1和DP2)的接口,因?yàn)镈P1和DP2是兩個(gè)已經(jīng)存在的程序所為我們無(wú)法直接抽象出DP1和DP2的高層接口,通過(guò)一種間接方式抽象出高層接口,使用抽象類把變化封裝在它的“后面”,接著我們就是要在抽象類Shape和DrawingProgramming直接建立依賴關(guān)系了(優(yōu)先使用對(duì)象聚集,而不是繼承),所以可以通過(guò)在其中一個(gè)抽象類中保持對(duì)方的引用就OK了,但究竟是哪個(gè)類依賴于哪個(gè)類呢?

            這里存在兩種情形:

            一、DrawProgramming類保存Shape對(duì)象引用

            二、Shape類保存DrawProgramming對(duì)象引用

            首先考慮第一種情形,如果在DrawProgramming保存Shape對(duì)象引用,我們通過(guò)調(diào)用Draw()方法繪制圖形,但它們必需對(duì)Shape類中的圖形有所了解(Draw()方法將具體圖形封裝了),當(dāng)我們使用OperationalDP1中的DrawCircle()方法時(shí),就要知道Shape中的Circle類型,這違反了對(duì)象應(yīng)該只對(duì)自己負(fù)責(zé)。

       

       bridge7

      圖6 情形一

       

            第二種情形,如果Shape對(duì)象使用DrawProgramming對(duì)象繪制圖形時(shí),圖形無(wú)需知道具體繪圖程序。當(dāng)使用Circle中的Draw()方法我們只需要調(diào)用DrawProgramming中的方法DrawCircle(),因此可以讓Shape保存DrawProgramming的對(duì)象引用。

       

      clip_image002

      圖6 情形二

       

            通過(guò)分析我們可以確定采用情形二實(shí)現(xiàn)起來(lái)相對(duì)簡(jiǎn)單,接著在抽象類Shape增加DrawProgramming對(duì)象引用,從而在Shape和DrawProgramming之間建立了一種聚集關(guān)系(has – a關(guān)系)。

            現(xiàn)在讓我們回憶一下橋接模式(Bridge)的定義:將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。Shape類及其實(shí)現(xiàn)就是抽象部分,而DrawingProgramming及其實(shí)現(xiàn)是具體部分,通過(guò)聚集使得它們分離開(kāi)來(lái),從而應(yīng)對(duì)變化和擴(kuò)展更加靈活。

       

       bridge9

      圖7 橋接模式實(shí)現(xiàn)繪圖程序

       

            我們已經(jīng)完成了繪圖程序的類設(shè)計(jì),而且通過(guò)該程序類設(shè)計(jì)我們了解到了橋接模式(Bridge)的作用,現(xiàn)在讓我們通過(guò)具體代碼完成繪圖程序。

       

      /// <summary>
      /// As Abstraction.
      /// </summary>
      public abstract class Shape
      {
          /// <summary>
          /// Has a reference from DrawingProgramming.
          /// </summary>
          private DrawingProgramming _dp;
      
          public Shape()
          {
          }
      
          public Shape(DrawingProgramming dp)
          {
              this.Dp = dp;
          }
      
          public abstract void Draw();
      
          public DrawingProgramming Dp
          {
              get { return _dp; }
              set { _dp = value; }
          }
      
      }
      
      
      /// <summary>
      /// As Refined Abstraction.
      /// </summary>
      public class Retangle : Shape
      {
          private int _width = 0;
          private int _height = 0;
      
          public Retangle(DrawingProgramming dp, int width, int height)
              : base(dp)
          {
              this.Width = width;
              this.Height = height;
          }
      
          public override void Draw()
          {
              this.DrawRetangle(Width, Height);
          }
      
          public void DrawRetangle(int width, int height)
          {
              this.Dp.DrawRetangle(width, height);
          }
      
          public int Width
          {
              get { return _width; }
              set { _width = value; }
          }
      
          public int Height
          {
              get { return _height; }
              set { _height = value; }
          }
      
      }
      
      /// <summary>
      /// As Refined Abstraction.
      /// </summary>
      public class Triangle : Shape
      {
          private int _rows = 0;
      
          public Triangle(DrawingProgramming dp, int rows)
              : base(dp)
          {
              this.Rows = rows;
          }
      
          public override void Draw()
          {
              this.DrawTriangle(this.Rows);
          }
      
          public void DrawTriangle(int rows)
          {
              this.Dp.DrawTriangle(rows);
          }
      
          public int Rows
          {
              get { return _rows; }
              set { _rows = value; }
          }
      }
      
      
      /// <summary>
      /// As Implementor.
      /// </summary>
      public abstract class DrawingProgramming
      {
          /// <summary>
          /// Abstract draw method.
          /// </summary>
          /// <param name="width"></param>
          /// <param name="height"></param>
          public abstract void DrawRetangle(int width, int height);
      
          public abstract void DrawTriangle(int Rows);
      }
      
      
      /// <summary>
      /// As concrete Implementor
      /// </summary>
      public class OperationalDP1 : DrawingProgramming
      {
          public OperationalDP1()
          {
          }
      
          public DP1 DP1
          {
              get
              {
                  throw new System.NotImplementedException();
              }
              set
              {
              }
          }
      
          public override void DrawRetangle(int width, int height)
          {
              DP1.DrawRetangle(width, height);
          }
      
          public override void DrawTriangle(int Rows)
          {
              DP1.DrawTriangle(Rows);
          }
      }
      
      /// <summary>
      /// As concrete Implementor
      /// </summary>
      public class OperationalDP2 : DrawingProgramming
      {
      
          public OperationalDP2()
          {
          }
      
          public DP2 DP2
          {
              get
              {
                  throw new System.NotImplementedException();
              }
              set
              {
              }
          }
      
          public override void DrawRetangle(int width, int height)
          {
              DP2.DrawRetangle(width, height);
          }
      
          public override void DrawTriangle(int Rows)
          {
              DP2.DrawTriangle(Rows);
          }
      }
      
      /// <summary>
      /// existed drawing programming.
      /// </summary>
      public class DP1
      {
          /// <summary>
          /// Concrete draw method.
          /// </summary>
          /// <param name="width"></param>
          /// <param name="height"></param>
          public static void DrawRetangle(int width, int height)
          {
              for (int i = 0; i < height; i++)
              {
                  for (int j = 0; j < width; j++)
                  {
                      Console.Write("■");
                  }
                  Console.WriteLine();
              }
          }
      
          public static void DrawTriangle(int Rows)
          {
              for (int i = 0; i < Rows; i++)
              {
                  for (int j = 0; j < i + 1; j++)
                  {
                      Console.Write("■");
                  }
                  Console.WriteLine();
              }
          }
      }
      
      /// <summary>
      /// existed drawing programming.
      /// </summary>
      public class DP2
      {
          /// <summary>
          /// Concrete draw method.
          /// </summary>
          /// <param name="width"></param>
          /// <param name="height"></param>
          public static void DrawRetangle(int width, int height)
          {
              for (int i = 0; i < height; i++)
              {
                  for (int j = 0; j < width; j++)
                  {
                      Console.Write("★");
                  }
                  Console.WriteLine();
              }
          }
      
          public static void DrawTriangle(int Rows)
          {
              for (int i = 0; i < Rows; i++)
              {
                  for (int j = 0; j < i + 1; j++)
                  {
                      Console.Write("★");
                  }
                  Console.WriteLine();
              }
          }
      }

      brideg10 圖8 繪圖程序

           通過(guò)上面的例子我們對(duì)橋接模式(Bridge)有了初步的了解,假設(shè)我們的繪圖程序DP1擁有特有擦除方法Wipe(),從而需要在OperationalDP1類中增加相應(yīng)的方法,但沒(méi)有必要修改DrawingProgramming類,現(xiàn)在問(wèn)題出現(xiàn)了我們要在抽象類Shpe中增加Wipe()方法,但這種修改是我們?cè)敢饪吹降?。這時(shí)我們可以考慮以下兩種方法解決問(wèn)題。

      方法一:在基類中添加虛的方法,然后需要的子類重寫(xiě)基類的虛方法。

      方法二:使用.NET Framework中的擴(kuò)展方法,對(duì)基類方法進(jìn)行擴(kuò)展。

       

       

      1.1.3 總結(jié)

           橋接模式(Bridge)優(yōu)點(diǎn):

           將實(shí)現(xiàn)予以解耦,讓它和界面之間不再永久綁定。

           抽象和實(shí)現(xiàn)可以獨(dú)立擴(kuò)展,不會(huì)影響到對(duì)方。

           對(duì)于具體實(shí)現(xiàn)的修改,不會(huì)影響到客戶端。

       

           橋接模式(Bridge)缺點(diǎn):

           增加了設(shè)計(jì)復(fù)雜度。

           抽象類的修改影響到子類。

       

           橋接模式(Bridge)用途:

           適用在需要跨多平臺(tái)的圖形和窗口系統(tǒng)。

           當(dāng)需要用不同的方式改變接口和實(shí)現(xiàn)時(shí)。

           通過(guò)上述的介紹,我們了解為什么需要橋接模式(Bridge)和如何使用橋接模式(Bridge),由于對(duì)象的多維度的變化,使得難以決定變化時(shí),我們可以把對(duì)象和變化抽象出來(lái)。

           如果我們的對(duì)象依賴于抽象,對(duì)于具體的實(shí)現(xiàn)并不關(guān)心,我們可以通過(guò)對(duì)象組合,組合出我們想要的對(duì)象。橋接模式符合OCP(對(duì)于擴(kuò)展開(kāi)發(fā),對(duì)于修改關(guān)閉)設(shè)計(jì)模式的原則。

      posted @ 2011-06-29 20:39  JK_Rush  閱讀(18734)  評(píng)論(11)    收藏  舉報(bào)
      主站蜘蛛池模板: 九九热热久久这里只有精品| 亚洲春色在线视频| 亚洲日韩乱码中文无码蜜桃臀| 九九热在线视频精品免费| 美女爽到高潮嗷嗷嗷叫免费网站| 亚洲欧美一区二区成人片| 久久久久影院色老大2020| 最新国产精品中文字幕| 亚洲国产高清在线观看视频| 国产精品午夜福利视频| 国产亚洲999精品AA片在线爽| 人妻系列中文字幕精品| 久久夜色精品国产亚洲av| 永久免费无码av网站在线观看| 成人国产亚洲精品一区二区| 精品视频一区二区| 1精品啪国产在线观看免费牛牛| 国产精品一区免费在线看| 亚洲 中文 欧美 日韩 在线| 国产精品v欧美精品∨日韩| 在线天堂最新版资源| 无码人妻斩一区二区三区| 日本一本无道码日韩精品| 麻豆国产va免费精品高清在线| 国产一区二区三区不卡观| 强奷漂亮少妇高潮麻豆| 亚洲精品日韩在线丰满| 18禁免费无码无遮挡网站| 日韩精品亚洲专区在线播放| 精品91在线| 日韩av片无码一区二区不卡| 亚洲国产成人久久77| 在线精品视频一区二区三四| 国产午夜精品理论大片| 国产裸体无遮挡免费精品| 亚洲成人av综合一区| 久热这里只有精品视频3| 国产蜜臀视频一区二区三区 | 男女啪啪高潮激烈免费版| 亚洲人成在线观看网站不卡| 色婷婷久久综合中文久久一本|