今天,我们来学习下建造者模式,这个模式,听名字就知道和建筑有关系嘛,建筑在我们日常生活中相当常见,建筑它有什么特点呢?首先,它们都有墙,有门,有窗等等,总而言之,言而总之,它们都是由固定的模式组合而成的,今天,就让我们按照建造房子的模式来学习这个建造者模式。。
今天的场景,我们不是建房子,我们在电脑上建造一个小人,和房子一个道理,每个人都有头,手,脚,身体等等一系列构成,好的,开始我们的学习,首先,设计模式第一步,抽象,上代码
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哈哈~),好了,今天的建造者模式就学完了,最后,总结一下吧,建造者模式只适用在一些亘古不变的场景下使用,例如我们今天说的房屋和人,这些部件它们都是不会如何变化的。。
设计模式虽然巧妙,但是也不可滥用