一段对话讲完建造者模式
截止今天,小秋学习Java刚刚满三个月。此刻的小秋感觉自己Java学的还不错,想去帅地面前炫耀一番,于是,就发生了一下一番对话.....
得意的小秋
帅地:嗨,小秋,看你今天气色不错啊。最近Java学的怎么样了?
小秋:说实话,比起三个月前我学指针的那段日子,这Java太友好了,感觉就是分分种的事(暗自得意)。
帅地:我靠,你这口气还挺大啊。从c的面向过程到Java的面向对象,还习惯不?
小秋:哎,还行,无非就是“一切皆对象”,Java中的对象感觉类似于C中的结构体。反正不过三七二十一,我脑子里都把他们当成是一个对象就得了。(内心自我感觉良好)
帅地:看你也学了三个月了,要不我随便拿道题考考你?(让你不谦虚,暗自偷笑)
小秋:好啊,正好练练手(嘿嘿,终于可以展现实力了)。
重载多次的构造函数
帅地:假如有一个蛋糕Cake对象,蛋糕这个对象有一个必选属性size,还有一些可选属性apple,banana,orange,mango等,必选属性代表用户必须要指定蛋糕的大小,可选属性代表这些蛋糕要加哪些材料。
小秋:这个很简单啊,创建一个Cake类,里面有size,apple,banana,orange,mango属性,然后构造器的参数里指定size这个参数就可以了。我直接上代码吧:
public class Cake { private int size; private String apple; private String banana; private String orange; private String mango; //new时必须给出size public Cake(int size) { this.size = size; } }
帅地:可选参数呢?我要new一个size=30,并且添加apple的蛋糕怎么办?
小秋:哦,我写的太快,忘了重载了,稍等(心想,这还不简单)。
public class Cake { private int size; private String apple; private String banana; private String orange; private String mango; public Cake(int size) { this.size = size; } public Cake(int size, String apple) { this.size = size; this.apple = apple; } public Cake(int size, String apple, String orange) { this.size = size; this.apple = apple; this.orange = orange; } public Cake(int size, String apple, String orange, String mango) { this.size = size; this.apple = apple; this.orange = orange; this.mango = mango; } }
小秋:这下总可以了吧,你要加哪些料,你就使用哪个构造器。全部给你重载了。
帅地:(露出狡猾的表情)写构造函数倒是挺快的,那如果我要只加apple和mango的蛋糕呢?
小秋:啊?好吧,你这是逼我把所有组合的构造器都写出来。
于是,小秋把所有构造器的组合都写了出来。由于size是个必须参数,把其他四个可选参数进行组合,一共有16种。
噼里啪啦,劈里啪啦,小秋一口气把他们全部写出来了
public class Cake { private int size; private String apple; private String banana; private String orange; private String mango; public Cake(int size){ this.size = size; } public Cake(int size, String apple){ this.size = size; this.apple = apple; } public Cake(int size, String banana){ this.size = size; this.banana = banana; } ..... }
小秋:好了,这下,你要啥组合有啥组合了。
帅地:四个可选参数你就写了这么一大堆参数了。确定这样写?
小秋:我觉得挺好的啊,反正很快,多写几个就多写几个吧。
帅地:那如果给你6个可选参数呢?
这时候小秋偷偷算了一些,发现一共有74种组合?
小秋:不就是74种组合,我觉得问题不是很大(心有点虚)。
帅地:那万一有10个可选参数呢?
小秋:.....
帅地:而且你重载那么多构造器,用户在在new的时候,第一个参数和第二个参数代表什么,用户混乱了怎么吧?例如,你有个apple+banana的构造器
public Cake(int size, String apple, String banana){ this.size = size; this.apple = apple; this.banana = banana; }
但是用户在new的时候,可能忘记了参数的顺序
Cake cake = new Cake(size,“banana”,“apple”)。
小秋:我会提供相应的文档啊,忘记了可以看文档勒。
帅地:几百个构造函数,而且还那么相似,你去看下文档试试,然后说说你的心情。
小秋:......(不知所措)。
通过Javabean的模式
帅地:有没其他什么办法?
小秋:我想到另一种办法了,我可以通过set和get方法来设置可选参数的。我直接上代码你看看
public class Cake { private int size; private String apple; private String banana; private String orange; private String mango; public Cake(int size) { this.size = size; } //通过set来添加材料 public void setApple(String apple) { this.apple = apple; } public void setBanana(String banana) { this.banana = banana; } public void setMango(String mango) { this.mango = mango; } public void setOrange(String orange) { this.orange = orange; } }
此时的小秋有点得意....
帅地:挺不错,这种方法比刚才的好多了,又简洁。
此时如果要new一个apple+orange+mango的蛋糕的话,代码如下:
Cake cake = new Cake(30); cake.setApple("apple"); cake.setOrange("orange"); cake.setMange("mange");
参数依赖检查问题
帅地:这种方法也是有缺点,例如用构造器重载时一行代码就可以搞定了,现在要用四行代码。
小秋:反正我觉得这样很nice(得意中...)。
帅地:不过这样写有一个致命的缺点,假如那些属性之间存在依赖性的话,怎么办?例如Cake多了A,B两个属性,并且这两个属性之间存在依赖关系。如果你设置了属性A,但是没有设置属性B,那么这个Cake对象就会出问题。或者属性的先后顺序设置也可能会导致出现问题。对于这种情况,你在什么地方检查这种相互依赖的逻辑?
小秋:有点蒙蔽,不知所措....。
小秋:那你说怎么办?
静态内部类
帅地:其实你已经做的相当不错了,不过我今天就教你另外一个办法,我们可以开放一个静态内部类专门用来与外界打交道,用来收集用户想要设置的属性并且做检查。直接上代码:
public class Cake { private int size; private String apple; private String banana; private String orange; private String mango; //private,让外面无法直接创建 private Cake(Builer builer) { this.size = builer.size; this.apple = builer.apple; ..... } //专门用来与外界打交道 public static class Builer { private int size; private String apple; private String banana; private String orange; private String mango; public void setSize(int size) { this.size = size; } //为了省点代码,其他的省略 public Cake build() { //检查参数之间的依赖关系是否正确 return new Cake(this); } ..... } }
假如我要new一个apple+orange的Cake
Cake.Builer builer = new Cake.Builer(); builer.setSize(30); builer.setApple("apple"); builer.setOrange("orange"); //创建一个蛋糕 Cake cake = builer.build();
帅地:这种方法牛吧?这还不够,我们还可以采用链式调用的方法。
链式调用
public class Cake { private int size; private String apple; private String banana; private String orange; private String mango; //private,让外面无法直接创建 private Cake(Builer builer) { this.size = builer.size; this.apple = builer.apple; ..... } //专门用来与外界打交道 public static class Builer { private int size; private String apple; private String banana; private String orange; private String mango; //返回参数改为Builer public Builer setSize(int size) { this.size = size; return this; } public Builer setApple(String apple) { this.apple = apple; return this; } //为了省点代码,其他的省略 public Cake build() { //检查参数之间的依赖关系是否正确 return new Cake(this); } } }
如何使用?
Cake cake = new Cake.Builer() .setSize(30) .setApple("apple") .setOrange("orange") .build();
一行代码就搞定了。
帅地:厉害吧?
小秋:涨知识了,看来我还是太年轻了,以后得好好向帅地学习。
建造者模式
帅地:其实,上面那种方法算是23种设计模式中的其中一种---建造者模式。不过这只是一个简化版的建造者模式。
对于建造者模式,具体的UML图是这样的:
在这个UML图中,Builder是一个接口,定义一套规范,而我们使用的例子中,没有使用接口,直接使用具体类,但核心思想还是一样的。
其核心思想就是:将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
小秋:哇,强啊。我要给你点赞.....
算是第二次采取对话的方式写....,以后会多采取这种方式来写勒。
完
关注公我的众号:苦逼的码农,获取更多原创文章,后台回复礼包送你一份时下热门的资源大礼包。同时也感谢把文章介绍给更多需要的人

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
【Java】设计模式
设计模式实际上就是针对某一类问题的最优解决方案,代表了最佳的实践,是开发人员经过相当一段时间的试验总结得到的。 目的是为了重用代码,让代码更容易理解,也更具可靠性,就像一个个模具。总共有23种设计模式,分为三大类:创建型:关注于对象的实例化结构型:如何组合对象与类行为型:对象之间的交互通信 六大原则:1.开闭原则:对扩展开放,对修改关闭。2.里氏代换原则3.依赖倒转原则4.接口隔离原则5.迪米特法则6.合成复用原则 常见的设计模式 【1.单例模式】 意图:保证一个类只有一个实例,并提供一个访问它的全局访问点主要解决:一个全局使用的类频繁地创建与销毁何时使用:控制实例数目,节省系统资源关键代码:构造函数是私有的优点:内存只有一个实例,减少内存的开销;避免对资源的多重占用缺点:没有接口,不能继承 实现:创建一个类,类有私有的构造函数和本身一个静态实例,该类提供一个静态方法,供外界获取静态实例。【懒汉式】声明对象,在调用getinstance()方法才创建对象【饿汉式】声明并创建对象 【2.工厂模式】 意图:定义一个创建对象的接口,让子类自己决定实例化哪个工厂类,使创建过程延迟到子类进行主要...
- 下一篇
PHP中关于时间(戳)、时区、本地时间、UTC时间等的梳理
PHP中关于时间(戳)、时区、本地时间、UTC时间等的梳理 在PHP开发中,我们经常会在时间问题上被搞糊涂,比如我们希望显示一个北京时间,但是当我们使用date函数进行输出时,却发现少了8个小时。几乎所有的php猿类都必须对php中几个重要的时间转换等方法进行研究。本文就来梳理这些问题。 时间戳(timestamp) GMT 在时间戳这个点上,它是一个概念,而不是具体的编程问题,是计算机世界通用的一种约定。时间戳是指格林尼治时间(GMT)1970年01月01日00时00分00秒到当前时间的总秒数。 GMT(也被称为世界时)是固定为本初子午线经过地区的时间,因此被作为时间参照物。 UTC 协调世界时(UTC)和GMT一样都是一种时间的参照物,但是他们的计算方法不同UTC是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统,从精度上讲,更加精确(自然也比GMT更精确),因此被称世界统一时间,世界标准时间,国际协调时间。 Unix时间戳 Unix时间戳是在计算机领域才有的,每一台电脑(服务器)在生产的时候,将GMT/UTC的1970年01月01日00时00分00秒作为起始值进行计...
相关文章
文章评论
共有0条评论来说两句吧...