今天,我們來學習下建造者模式,這個模式,聽名字就知道和建築有關係嘛,建築在我們日常生活中相當常見,建築它有什麼特點呢?首先,它們都有牆,有門,有窗等等,總而言之,言而總之,它們都是由固定的模式組合而成的,今天,就讓我們按照建造房子的模式來學習這個建造者模式。。
今天的場景,我們不是建房子,我們在電腦上建造一個小人,和房子一個道理,每個人都有頭,手,腳,身體等等一系列構成,好的,開始我們的學習,首先,設計模式第一步,抽象,上程式碼
abstract class PersonBuider { protected Graphics g; protected Pen p; public PersonBuider(Graphics g, Pen p) { this.g = g; this.p = p; } public abstract void BuidHead(); public abstract void BuidBody(); public abstract void BuidArmLeft(); public abstract void BuidArmRight(); public abstract void BuidLegLeft(); public abstract void BuidLegRight(); }
上面這個PersonBuider類,看名字就知道大概了,我們分析下它裡面的內容,首先,建構函式注入,幾乎設計模式都用到的東西,注入兩個環境提供的類,畫布和畫筆,然後是定義了六個抽象方法,對應的我們的身體各部,其實也很簡單,一目瞭然,接下來,根據以往的套路來看,既然定義了抽象,那麼肯定就要實現了啊。這是必須的,不然抽象就無用了呢
class PersonThinBuilder : PersonBuider { public PersonThinBuilder(Graphics g, Pen p) : base(g, p) { } public override void BuidHead() { g.DrawEllipse(p, 50, 20, 30, 30); } public override void BuidBody() { g.DrawRectangle(p, 60, 50, 10, 50); } public override void BuidArmLeft() { g.DrawLine(p, 60, 50, 40, 100); } public override void BuidArmRight() { g.DrawLine(p, 70, 50, 90, 100); } public override void BuidLegLeft() { g.DrawLine(p, 60, 100, 45, 150); } public override void BuidLegRight() { g.DrawLine(p, 70, 100, 85, 150); } }
這裡,我們建立一個PersonThinBuilder類實現了PersonBuider類,誒,這裡,我們又看到了上次裝飾器模式裡的建構函式注入,它用了base關鍵字,這個關鍵字的作用我們在裝飾器一文程式碼中有註釋,是呼叫父類建構函式的意思,為什麼要這麼寫呢,我們先看完建造者模式所有骨架之後我們再來分析一波,好的,我們的PersonThinBuilder實現類,重寫了我們抽象類的六個抽象方法,這裡就是建立我們具體的人的各個部位,好了,現在我們都具備了建立各個零件的能力,接下來,就是去實際生成了
class PersonDirector { private PersonBuider pb; public PersonDirector(PersonBuider pb) { this.pb = pb; } public void CreatePerson() { pb.BuidHead(); pb.BuidBody(); pb.BuidArmLeft(); pb.BuidArmRight(); pb.BuidLegLeft(); pb.BuidLegRight(); } }
看到我們這個PersonDirector類的建構函式應該不陌生了吧,它再一次的用了建構函式注入,這次,它注入的是我們的抽象類PersonBuider,然後它自身有一個方法,這個方法的內部就是分別呼叫了抽象類的六個抽象方法,到這裡,我們建造者模式的所有骨架基本完成了,現在,讓我們看看上層呼叫實現,是如何把一個小人給組合起來的吧
public void DrawPerson() { Pen p = new Pen(Color.Red); PersonThinBuilder ptb = new PersonThinBuilder(pictureBox1.CreateGraphics(), p); PersonDirector pdThin = new PersonDirector(ptb); pdThin.CreatePerson(); } private void button1_Click(object sender, EventArgs e) { DrawPerson(); }
這裡我們用的是winForm去實現,這樣我們能更清晰的看到效果,上面的程式碼就是上層的實現了,首先,它new了一個PersonThinBuilder類,然後再new了一個PersonDirector類,這裡,我們解釋一下剛才我們的疑問,首先是new一個PersonThinBuilder類,我們注意到,它例項化的時候傳了一個畫布例項和一個畫筆例項,這是為什麼呢,因為它繼承了PersonBuider類,當我們去例項化PersonThinBuilder的類的時候,如果這個時候我們去除錯程式碼就會知道,它會率先去例項PersonBuider類,而PersonBuider類的例項需要一個畫布和一個畫筆,所以,我們在new一個PersonThinBuilder類的時候才傳入這兩個物件的,所以,這才能解釋為什麼PersonThinBuilder ptb = new PersonThinBuilder(pictureBox1.CreateGraphics(), p);這個語句會成立的根本原因。接下來,我們來解釋下為什麼要這麼傳參,就是所謂的建構函式注入,建構函式注入的用意在於解耦,在類關係中,組合關係是類和類關係最鬆散的一種,使用建構函式注入,可以讓我們不用在呼叫類的裡面去例項我們需要呼叫的型別,而是把它們延遲到我們的最上層是例項,意思就是在我們寫程式碼的時候不用去new它,而是在我們上端實現的時候去new它,這也解釋了PersonThinBuilder類建構函式為什麼用base這個關鍵字了,因為在PersonThinBuilder類的內部我們根本沒有用到,所以無需建構函式注入,PersonThinBuilder類的構造只是起到一個橋樑作用。好了,疑問解答完畢,接下來,讓我們看看我們實現的小人吧
這個就是我們大費周章得到的小人了,一看就知道骨骼清奇(O(∩_∩)O哈哈~),好了,今天的建造者模式就學完了,最後,總結一下吧,建造者模式只適用在一些亙古不變的場景下使用,例如我們今天說的房屋和人,這些部件它們都是不會如何變化的。。
設計模式雖然巧妙,但是也不可濫用