这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战java
欢迎来到今天的学习,今天咱们一块儿来唠唠建造者模式。多唠叨几句,前面我有提到本月将会对java的设计模式精讲,欢迎点击头像,关注个人专栏,我会持续更新,加油!算法
系列文章:编程
设计模式之单例模式设计模式
设计模式之工厂模式markdown
....系列持续更新框架
话很少话,进入正题ide
建造者模式是另一个高频使用的建立型设计模式——一般叫 Builder 模式,中文通常叫建造者模式或生成器模式。函数
今天咱们改变下策略,先开始不讲原理,先从例子下手,从解决问题案例当中去寻求答案。你认为的那种答案。oop
先看建造者模式主要带来什么或者解决什么问题:post
直接使用构造函数或者使用 set 方法来建立对象方不方便?,有没有一种简单的方法建立对象
存在的价值,为何须要建造者模式建立对象
下面经过代码具体深刻理解,咱们只讲干货,让你看完就能解决如今你代码中的实际问题!
对同一种场景咱们用建造者模式和不用建造者模式来进行代码对比:
很简单,咱们建立学生对象
/** * 学生实体 * 不用建造者模式 */
public class Students {
private String name; //姓名
private int age; //年龄
private String grade; //班级
private String gender; //性别
public Student(String name, int age, String grade, String gender) {
this.name = name;
this.age = age;
this.grade = grade;
this.gender = gender;
}
public Student(String name, int age, String grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
//上述代码写了三个不一样参数的构造函数
public static void main(String[] args) {
Student student01 = new Student("张三",26,"13班","男");
Student student02 = new Student("张三",26,"13班");
...
}
复制代码
上述有问题吗,没有问题。这代码能够吗,你以为呢?问题显而易见(确定还有不少小伙伴日常工做中都是这么搞的)。上面这段代码没有使用建造者模式,因此咱们须要使用传统的 getter、setter 方法,并指定不一样的入参来构造对象。若是参数过多,业务比较多,那须要建立太多构造方法。
而使用建造者模式后的类,功能却发生了彻底不同的变化,以下所示:
/** * 学生实体 * * 使用建造者模式建立对象 */
public class Students {
//全部属性
private String name;
private int age;
private String grade;
private String gender;
public Students() {
}
//内部builder new对象
public static Students builder() {
return new Students();
}
//将属性做为步骤
public Students name(String name) {
this.name = name;
return this;
}
//将属性做为步骤
public Students age(int age) {
this.age = age;
return this;
}
//将属性做为步骤
public Students grade(String grade) {
this.grade = grade;
return this;
}
//将属性做为步骤
public Students gender(String gender) {
this.gender = gender;
return this;
}
//执行建立操做(最后封口return)
public Students build() {
validateObject(this);
return this;
}
private void validateObject(Students Students) {
//能够作基础预校验,或自定义校验
}
@Override
public String toString() {
return "Students{" +
"name='" + name + '\'' +
", age=" + age +
", grade='" + grade + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
//用建造者模式来建立对象
public static void main(String[] args) {
//建立对象
Students st = Students.builder()
.name("张三")
.age("26")
.grade("13班")
.gender("男")
.build();
//建立对象
Students st01 = Students.builder()
.name("张三")
.age("26")
.grade("13班")
.build();
//一步步建造一个个属性
}
复制代码
这,就是建造者模式来搞定对象。咱们能够发现构建出了彻底不一样的对象实例,而使用传统的 getter、setter 方法,则须要写不少不一样的构造函数来应对变化。
因此说,使用建造者模式能更方便地帮助咱们按需进行对象的实例化,避免写不少不一样参数的构造函数,同时还能解决同一类型参数只能写一个构造函数的弊端。
虽然上面案例的实现比较简单,可是也充分演示了如何使用建造者模式。在实际的使用中,一般能够直接使用 lombok 的 @Builder 注解实现类自身的建造者模式
为何要使用建造者模式来建立类?在我看来,有如下几点缘由。
第一,分步骤的属性赋值更适合屡次运算结果类建立场景。在面向对象软件开发中,不少时候建立类所须要的参数并非一次都能准备好的,好比,计算订单优惠价格、查询库存状态等,有的参数可能须要经过调用多个服务运算后才能得出,这时咱们能够根据已知参数预先对类进行建立,等有合适的参数时再设置类的属性,而不是等到全部结果都齐备后才去建立类。
第二,不须要关心特定类型的建造者的具体算法实现。 好比,咱们在使用 StringBuilder 时,并不太关心它的具体代码实现,而是关心它提供给咱们的使用功能。这在某些须要快速复用的场景中,能起到提高编码效率的做用。
第三,提升代码的可阅读性,简洁明了,须要哪一个功能(属性),就调用哪一个,方便阅读,可维护性强。内部属性扩展性极强,自由地组合对象属性。
第四知足开闭原则,这也是设计模式的优势。 每个建造者都相对独立,所以能方便地进行替换或新增,这就大大提高了代码的可扩展性。
固然,夸奖完,仍是要指出一些存在一些客观性存在的问题。
使用范围有限。 建造者模式所建立的对象通常都须要有不少的共同点,若是对象实例之间的差别性很大,则不适合使用建造者模式。
容易形成超类,业务繁多,新的建立步骤就会被加进来,这会形成代码量的急剧膨胀,类会变得臃肿,最终造成一个庞大的超大类。
咱们来看下Netty框架当中是怎么运用建造者模式的(Netty不懂的自行百度下,后续我会对Netty做出专题来说)。
你们还记得,在服务端启动的时候有个启动辅助类ServerBootStrap,咱们调用group方法、channel方法设置参数。这里面也使用了这种建造者链式编程来设置相关参数。
ServerBootstrap b = new ServerBootstrap();
//开始建立对象
b.group(bossGroup, workerGroup) //bossGroup和workerGroup 先不用管,本节主要讲建造者模式
//赋值channel参数
.channel(NioServerSocketChannel.class)
//赋值option参数
.option(ChannelOption.SO_BACKLOG, 100)
//赋值handler参数
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
System.out.println("服务启动");
}
});
复制代码
下面咱们来一块儿看下源码,源码我就直接从idea当中截图了,我会从中圈出重点:
先看group,设置完参数以后,便返回this对象
再看 childHandler,依然如此,是否是和咱们上面学生的例子是同样的
其余几个参数也是同样,你们能够自行看下。
OK,今天咱们的建造者模式就讲到这里,感谢你的阅读,相信你能从中学到东西。同时也很是欢迎您的点赞,关注和分享!
我已经将本章收录在专题里,点击文章下方专题,关注专栏,我会天天发表干货,本月我会持续输入设计模式。咱们下期再见!