Java 帝国之建造者模式

原创: 王钦誉 码农翻身 今天

本文来自王钦誉的投稿,老刘做了较大修改。

原文地址:

https://xiaoqinyu0000.github.io/2018/06/11/Java/JavaBuilder/

据说在帝国建立初期,人类眼里的Java程序就是一个黑乎乎的命令行窗口,里面显展示着大片大片的代码和文字。

那是一个灰暗的年代, 几乎没有人愿意天天与这些黑窗口打交道。

国王决心让帝国变得多姿多彩,于是下令建立图形村,研究Java的图形和图像。

经过艰苦卓绝的努力,我们掌握了GUI编程的核心技术,帝国终于可以在人类设备上展示图形界面了。

99个重载函数

我是图形村的一个代表,专门对外提供一种图形: Square(正方形)

给你看看我最近接的几个单子:

用户一的需求是一个50 * 50的蓝色正方形;

用户二的需求是一个50 * 50的蓝色正方形,还要一个黑色的边框;

…....

Square对象可以很简单(例如用户一要的就是一个蓝色的正方形),也可以非常复杂(形状、颜色、大小、边框、阴影、层次等等)。

用户需要什么样的图形,只需要把对应的属性(长、宽、颜色...)告诉我就行...

 1class Square {
2    public Square(int size, int color) { ... }
3
4    public Square(int size, int color, int borderColor) { ... }
5
6    public Square(int size, int color, int borderColor, float radius) { ... }
7
8    public Square(int size, int color, int borderColor, float radius, float strokeDashGap) { ... }
9
10    public Square(int size, int color, int borderColor, float radius, float strokeDashGap, float shadow) { ... }
11    ......
12}

(友情提示:可左右滑动)

为此,一个Square的构造函数, 我整整重载了99次!

不过带来的好处就是不管用户想要一个什么样的图形,只需调用一个方法,一行代码就可以搞定啦。

比如,用户1想要一个50*50的蓝色正方形,你需要给我3个参数便可以获得Square对象:

  • 大小:50 * 50

  • 颜色:Color.Blue

Square square = new Square(50, Color.Blue);

想再加一个黑色边框,只需要增加一个参数就行:

  • 边框:Color.Black

Square square = new Square(50, Color.Blue, Color.Black);

仅需一行代码就可以拿到Square对象,然后就可以在人类的设备上显示图形啦。

没有什么是一个重载方法解决不了的,如果有,那就两个重载方法…

每当有人抱怨说,从你这99个方法中找到一个合适的方法实在是太难了!  我就扔给他一个文档,里边详细描述着每个方法的参数,含义,只要读一遍,绝对没问题!

我的坚持引发了大家的怨气,当抱怨的人越来越多,我有点慌了,赶紧去找村长,希望他能给出点注意。

新设计

村长看了一会儿我的API,叹了口气说:“怪不得人家抱怨,你看看你的设计!”

Square square = new Square(50, Color.Red, Color.Blue, 5, Color.Black, 4, 9, Color.Red, 4, 8);

我一瞧,有什么奇怪的嘛?不就是创建一个Square对象吗?

他指着这行代码:“你看这行代码,能够清晰得知道要的是怎么样的图形吗?假设要你把阴影颜色改了,你知道改哪个值吗?”

我说:“稍等,我查下文档。”

3分钟后我说:“好像是改第5个参数吧。”

“每次用你的服务都要去查文档,从N个重载方法里找到对应所需的方法,再看看每个属性的含义,你觉得好用吗?” 村长厉声斥责。

我心想,这确实是问题,然而世间之事哪能十全十美呢?

我叹了口气:“Square 是复杂对象, 有很多属性和组合方式…有形状、颜色、长宽、边框、阴影、内外边距….”。

“你啊,真是不思进取,你想想,还有什么好的设计? ”

我说:“也许可以做出这样? ”

1class Square {
2    public Square() {...}
3    public void setSize(int size) {...}
4    public void setColor(int color) {...}
5    public void setBorderSize(int size) {...} 
6    public void setBorderColor(int color) {...}
7    public void setPadding(int left, int top, int right, int bottom) {...}
8    ...
9}

(友情提示:可左右滑动)

其实就是把各个属性拆分成各个方法,让用户去组合他们需要的属性!

1Square square = new Square();
2square.setColor(Color.Blue);
3square.setBorderSize(5);
4square.setBorderColor(Color.Black);

如何对参数进行检查?

村长说:“这其实是一种类似JavaBean的方法, 比之前好了一点,但是你想过这个问题没有? 假设一些属性依赖另外一些属性,如果设置了属性A,但是没有设置属性B,那Square对象其实是有问题的,对于这种情况,你怎么处理?你在什么地方检查这种互相依赖的逻辑? ”

村长一下子就击中我的要害了,果然有两下子。

我赶紧请教:“您有何高见?”

村长说道:“你可以开放一个静态内部类专门用来与外界打交道,来收集用户想要设置的参数并且做检查。”

 1class Square {
2
3    private int color;
4    private int borderSize;
5    ......
6    //private,让外面无法直接创建
7    private Square(Builder builder) {    
8        this.color = builder.color;
9        this.borderSize = builder.borderSize;
10        ......
11    }
12
13    public static class Builder {
14        private int color;
15        private int borderSize;
16        ......
17
18        public void setColor(int color) { }
19        public void setBorderSize(int size) { }    //边框大小
20        public void setBorderColor(int color) { }    //边框颜色
21        public void setPadding(int left, int top, int right, int bottom) { }
22        ...
23
24        public Square build() {
25            ...检查参数之间的关系是否设置正确...
26            return new Square(this);
27        }
28    }
29}

看到这个代码,我已经不由自主地在纸上模拟用户的使用场景了:

1Square.Builder builder = new Square.Builder();
2builder.setSize(50);
3builder.setColor(Color.Blue);
4builder.setBorderSize(5);
5builder.setBorderColor(Color.Black); 
6//在build方法中会检查参数是否正确。
7Square square = builder.build();

可是这个调用方式可是比我之前提供的API复杂得多呀!如果旧的API,只用一行代码就可以可以了!

链式调用

村长似乎看到了我的疑惑,笑了笑问到:”你知道链式调用吗?“。

紧接着,他又展示了一段代码,里面静态内部类Builder的所有设置属性的方法的返回值居然变了:

 1class Square {
2    ...
3    public static final class Builder {
4        public Builder setColor(int color) {
5            ......
6            return this;
7        }
8        public Builder setBorderSize(int size) {
9            ......
10            return this;
11        }
12        public Builder setBorderColor(int color) {
13            ......
14            return this;
15        }
16        public Builder setPadding(int left, int top, int right, int bottom) {
17            ......
18            return this;
19        }
20        ...
21        public Square build() {
22            ...检查参数之间的关系是否设置正确...
23            return new Square(this);
24        }
25    }
26}

每一个Builder都返回了一个this,可是这又有什么用呢。

结合之前对方说的链式调用,我内心突然想到某种可能!

赶紧对之前调用方式的Demo做了一点修改:

1Square square = new Square.Builder()
2    .setSize(50)
3    .setColor(Color.Blue)
4    .setBorderSize(5)
5    .setBorderColor(Color.Black)
6    .build();

居然用一行代码就完成了调用,而且每个方法和属性都是如此得清晰、如此的明了,让人陶醉其中,不能自拔!

“看来,好的API设计远远重要于一份面面俱到的文档。” 我不由地感慨。

建造者模式

村长说道:“是啊,其实这种方式有个名称,叫做建造者模式! 对于你这个场景很适用。”

“Builder模式? 23种设计模式之一, 我学习过,好像不是这样的啊?”  说着我展示了一个UML 类图。

“真是死脑筋,我们这个是个简化版嘛!你看看这个图,Client 可以认为就是Director, 对于Builder,我们没有没有接口,直接就是具体类。 核心思想还是一样的嘛!”

(完)

Java 帝国之建造者模式的更多相关文章

  1. 折腾Java设计模式之建造者模式

    博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...

  2. Java 设计模式之建造者模式(四)

    原文地址:Java 设计模式之建造者模式(四) 博客地址:http://www.extlight.com 一.前言 今天继续介绍 Java 设计模式中的创建型模式--建造者模式.上篇设计模式的主题为 ...

  3. java设计模式3——建造者模式

    java设计模式3--建造者模式 1.建造者模式介绍: 建造者模式属于创建型模式,他提供了一种创建对象得最佳方式 定义: 将一个复杂对象的构建和与它的表示分离,使得同样的构建过程可以创建不同的表示 主 ...

  4. java设计模式之四建造者模式(Builder)

    工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到 ...

  5. Java设计模式之三 ----- 建造者模式和原型模式

    前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...

  6. java设计模式3.建造者模式、原型模式

    建造者模式 一个产品常有不同的组成部分作为产品的零件,有些情况下,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用,有些时候,一个对象的一些性质必须按照某个顺序赋值才 ...

  7. Java设计模式之三建造者模式和原型模式

    建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.简单的来说就是将一个复杂的东西 ...

  8. 设计模式(Java语言)- 建造者模式

    前言 在日常的生活中,我们可以经常看到建造者模式的影子.比如,建造房子,那么房子就是一个产品,房子由门,窗,墙,地板等部门组成.然后包工头在建造房子的时候就根据设计好的图纸来建造,但是包工头并不是亲自 ...

  9. JAVA设计模式总结—建造者模式

    建造者模式 模式动机与定义 ​ 首先建造者模式的动机是为了创建复杂对象,简化传统的创建方法,提高创建的效率和可读性. ​ 像图中的这个例子,用户的需求是驾驶一辆汽车,但是对于用户来说是不需要了解汽车装 ...

随机推荐

  1. maven eclipse 第3方包

    C:\Users\3510\.m2\repository\myjar install:install-file -Dfile=C:\Users\3510\.m2\repository\myjar\al ...

  2. idea 创建的spingmvc 引入jquery后jquery函数始终不执行的原因

  3. git基本操作1

    1.创建版本库 在文件夹下,打开Git Bash Here ,然后执行git init,文件夹中会多出.git文件夹.(.git可能是隐藏的) 2.创建a.txt vim  a.txt ,并添加到版本 ...

  4. 用织梦建站如何去掉a这个目录,还有内容页的a

    1.另外建一个站点,将物理路径直接指向a即可. 2.去掉文章页生成的带a的路径: 只需要这一句话:  function='str_replace("/a","" ...

  5. HTML实现包含公共部分:通过ECMA6的模块化,纯前端实现类似jsp:include的功能

    以前一直是用 jsp:include 的方式来引入 html 头部的公共部分 php也有类似的方式 但以上两种,个人感觉都并不纯粹,本着折腾的精神,优化原有代码,解耦合 使用 ECMA6 的模块化方式 ...

  6. HTML元素类别及转换

    位置特性分类元素分为三类:块级元素,行内元素,行级块元素 1.块级元素(block)        特点: (1)可以设置宽高.内.外边距:               (2)独占一行(即前后均有换行 ...

  7. HDU 4344-Mark the Rope-大数素因子分解

    注意只有一个素因子的情况. #include <cstdio> #include <algorithm> #include <cstring> using name ...

  8. 洛谷P2764 最小路径覆盖问题

    有向无环图的最小路径点覆盖 最小路径覆盖就是给定一张DAG,要求用尽量少的不相交的简单路径,覆盖有向无环图的所有顶点. 有定理:顶点数-路径数=被覆盖的边数. 要理解的话可以从两个方向: 假设DAG已 ...

  9. POJ 2449 Remmarguts' Date (算竞进阶习题)

    A* + dijkstra/spfa 第K短路的模板题,就是直接把最短路当成估价函数,保证估价函数的性质(从当前状态转移的估计值一定不大于实际值) 我们建反图从终点跑最短路,就能求出从各个点到终点的最 ...

  10. Yahoo Programming Contest 2019 补题记录(DEF)

    D - Ears 题目链接:D - Ears 大意:你在一个\(0-L\)的数轴上行走,从整数格出发,在整数格结束,可以在整数格转弯.每当你经过坐标为\(i-0.5\)的位置时(\(i\)是整数),在 ...