• 建造者模式(11)


    今天,我们来讲一下建造者模式。

    一、案例

    我们来用winform画一个小人,一个头,一个身体,两只手,两条腿。

    我们一般想到的代码如下:

     1         /// <summary>
     2         /// 画小人
     3         /// </summary>
     4         /// <param name="sender"></param>
     5         /// <param name="e"></param>
     6         private void pictureBox1_Paint(object sender, PaintEventArgs e)
     7         {
     8             Graphics gThin = e.Graphics;
     9             Pen p = new Pen(Color.Black, 2);
    10             gThin.DrawEllipse(p, 50, 20, 30, 30);
    11             gThin.DrawRectangle(p, 60, 50, 10, 50);
    12             gThin.DrawLine(p, 60, 50, 40, 100);
    13             gThin.DrawLine(p, 70, 50, 90, 100);
    14             gThin.DrawLine(p, 60, 100, 40, 150);
    15             gThin.DrawLine(p, 70, 100, 85, 150);
    16         }

    运行的效果:

    嗯,好,下面,我们再画一个稍微胖一点的小人。

    代码如下:

     1         private void pictureBox2_Paint(object sender, PaintEventArgs e)
     2         {
     3             Graphics gThin = e.Graphics;
     4             Pen p = new Pen(Color.Red, 2);
     5             gThin.DrawEllipse(p, 50, 20, 30, 30);
     6             gThin.DrawEllipse(p, 45, 50, 40, 50);
     7             gThin.DrawLine(p, 50, 50, 30, 100);
     8             gThin.DrawLine(p, 80, 50, 100, 100);
     9             gThin.DrawLine(p, 60, 100, 45, 150);
    10         }

    运行效果如下

    咦,我们好像少花了条腿哦。

    哈哈,像这样粗心的情况我们经常出现

    二、演绎

    1、第一步演绎

     1     /// <summary>
     2     /// 建造瘦小人的类
     3     /// </summary>
     4     class PersonThinBuilder
     5     {
     6         private Graphics _g;
     7         private Pen _p;
     8 
     9         public PersonThinBuilder(Graphics g, Pen p)
    10         {
    11             this._g = g;
    12             this._p = p;
    13         }
    14         /// <summary>
    15         /// 建造小人
    16         /// </summary>
    17         public void Build()
    18         {
    19             _g.DrawEllipse(_p, 50, 20, 30, 30);
    20             _g.DrawRectangle(_p, 60, 50, 10, 50);
    21             _g.DrawLine(_p, 60, 50, 40, 100);
    22             _g.DrawLine(_p, 70, 50, 90, 100);
    23             _g.DrawLine(_p, 60, 100, 40, 150);
    24             _g.DrawLine(_p, 70, 100, 85, 150);
    25         }
    26     }

    客户端

    1         private void pictureBox1_Paint(object sender, PaintEventArgs e)
    2         {
    3             Pen p = new Pen(Color.Black);
    4             Graphics gThin = e.Graphics;
    5             PersonThinBuilder ptb = new PersonThinBuilder(gThin, p);
    6             ptb.Build();
    7         }

    我们进行了第一步的改革,看了一下代码,将客户端的画小人的过程一直到了一个类中,客户端只需要调用这个类就可以了,但是,这仍然没有解决我们上面提到的问题,如果我们要画一个胖一点的小人,我们还需要建一个类,然后再写一遍创建过程,很难保证落下什么东西(比如:少了一只手也说不定哦)

    好,那么我们到底该如何解决呢?

    下面就是我们将要介绍的 建造者模式。

     建造者模式:将一个对象复杂的构建,与它的表示分离,使得同样的构建,可以创建不同的表示。

    如果我们使用了建造者模式,那么,用户只需要指定建造的类型就可以得到他们了,而具体的建造的细节和过程就不需要知道了。

    那么,我们画小人的案例该怎样使用建造者模式呢?我们一步步来分析。

    画小人,都需要画,头、身体、左手、右手、左腿、右腿。

    好,下面呢,我们就先来定义一个抽象的画小人的类,将这个过程固定住,不让任何人遗忘当中的任何一步。

     1     abstract class PersonBuilder
     2     {
     3         protected Graphics G;
     4         protected Pen P;
     5 
     6         protected PersonBuilder(Graphics g, Pen p)
     7         {
     8             G = g;
     9             P = p;
    10         }
    11 
    12         public abstract void BuildHead();
    13         public abstract void BuildBody();
    14         public abstract void BuildArmLeft();
    15         public abstract void BuildArmRight();
    16         public abstract void BuildLegLeft();
    17         public abstract void BuildLegRight();
    18     }

    然后,我们需要建造一个瘦一点的小人,我们可以让瘦一点的小人去继承这个抽象类。那么这个类就必须重写抽象类中的方法了,要不编译不通过的。所以,画小人就不会丢三落四了。

     1     class PersonThinBuilder : PersonBuilder
     2     {
     3         public PersonThinBuilder(Graphics g, Pen p) : base(g, p)
     4         {
     5         }
     6 
     7         public override void BuildHead()
     8         {
     9             G.DrawEllipse(P, 50, 20, 30, 30);
    10         }
    11 
    12         public override void BuildBody()
    13         {
    14             G.DrawRectangle(P, 60, 50, 10, 50);
    15         }
    16 
    17         public override void BuildArmLeft()
    18         {
    19             G.DrawLine(P, 60, 50, 40, 100);
    20         }
    21 
    22         public override void BuildArmRight()
    23         {
    24             G.DrawLine(P, 70, 50, 90, 100);
    25         }
    26 
    27         public override void BuildLegLeft()
    28         {
    29             G.DrawLine(P, 60, 100, 40, 150);
    30         }
    31 
    32         public override void BuildLegRight()
    33         {
    34             G.DrawLine(P, 70, 100, 85, 150);
    35         }
    36     }

    同理,胖子小人类也用上面的方式,继承抽象类,代码差不多,就不在写了。

    这样就完事了吗?如果完事了的话,那么我在客户端调用的时候,还是需要调用类里面的方法,万一哪一个方法没有调用,也就会出现丢三落四的情况了,这根本没有解决问题呀。所以,到这里,我们还没有完事呢。

    建造者模式还有一个非常重要的类,指挥者类。指挥者类是用来控制建造过程的,同时它也是隔离用户与建造过程的关联的。

    好,下面我们来写一个指挥者类。

     1     class PersonDirector
     2     {
     3         private PersonBuilder pb;
     4         //用户告诉指挥者,我需要什么样的小人
     5         public PersonDirector(PersonBuilder pb)
     6         {
     7             this.pb = pb;
     8         }
     9         //根据用户的选择建造小人
    10         public void CreatePerson()
    11         {
    12             pb.BuildHead();
    13             pb.BuildBody();
    14             pb.BuildArmLeft();
    15             pb.BuildArmRight();
    16             pb.BuildLegLeft();
    17             pb.BuildLegRight();
    18         }
    19     }

    这样,指挥者类写好了。其实指挥者类就是根据用户的选择,来一步一步的建造小人,而建造的过程在指挥者里面已经完成了,用户就不需要知道了。

    那么,客户端就是这样的了。

    1         private void pictureBox1_Paint(object sender, PaintEventArgs e)
    2         {
    3             //瘦小人
    4             PersonBuilder pb = new PersonThinBuilder(e.Graphics, new Pen(Color.Black));
    5             //告诉建造者,我要创建一个瘦小人
    6             PersonDirector pd = new PersonDirector(pb);
    7             //开始创建
    8             pd.CreatePerson();
    9         }

    ok,这样就成功的将我们的案例用建造者模式构建出来了。

    好了,建造者模式今天就讲到这里了,下篇博文我们将 观察者模式


    本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持。

  • 相关阅读:
    Linux中配置别名
    Linux下的IO监控与分析
    RHEL6 Systemtap 安装笔记
    记一次多事件绑定中自己给自己设置的坑——click,dblclick,mousedown,mousemove,mouseup
    springboot打jar获取不到static静态资源文件问题
    关于springboot默认日志框架Slf4j+logback,自定义Appender问题
    spring 时间格式问题
    springboot 部署到tomcat,获取根路径问题。空格变为%20
    前后端分离 vue+springboot 跨域 session+cookie失效问题
    springboot 部署到tomcat中,项目总是重新部署
  • 原文地址:https://www.cnblogs.com/xiaomowang/p/6322026.html
Copyright © 2020-2023  润新知