引言
女娲造人🤏的时候,可能先捏个头,再捏个手,再捏个脚;也有可能先捏个脚,再捏个头,再捏个手。顺序是可变的,组件都一样,出来的可能是老人,男人,女人等等。
建造者模式的定义也是这样理解的,「将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示」,定义很花里胡哨,可以参考一下上面女娲造人的例子,就可以很快理解了。
使用场景
如果一个对象内部结构复杂,并且想把复杂对象的创建和使用分离。再具体点来说,就当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,就可以考虑使用构造者模式。
建造者模式的优点也很显而易见,封装性好、创建和使用分离,拓展性好、各个建造类之间独立、一定程度上解耦,缺点就是使用的时候,产生多余的 Builder 对象,一旦产品内部发生变化,建造者需要修改成本较大
Coding
我们来举一个简单的做菜例子,这边就简单举例,炒菜需要用到 调味料和食物,重写一下 toString 方法方便我们打印
public class Dishes {
/**
* 调味料
*/
private String condiment;
/**
* 主料
*/
private String food;
@Override
public String toString() {
return "Dishes{" + "condiment='" + condiment + ''' + ", food='" + food + ''' + '}';
}
}
我们需要一个内部类,去实现把调味料和食物放入我们的锅中
/**
* 静态内部类
*/
public static class FoodBuilder {
/**
* 调味料
*/
private String condiment;
/**
* 主料
*/
private String food;
public FoodBuilder buildCondiment(String condiment) {
this.condiment = condiment;
return this;
}
public FoodBuilder buildFood(String food) {
this.food = food;
return this;
}
public Dishes build() {
return new Dishes(this);
}
}
这里需要特别注意的是,我们的 buildCondiment、buildFood 是一个链式调用,所以返回的都是FoodBuilder这个类,最后需要一个 build方法,把我们的菜搞出来
最后再实现一个构造器,将我们的FoodBuilder传进去
private Dishes(FoodBuilder foodBuilder) {
/**
* 调味料
*/
this.condiment = foodBuilder.condiment;
/**
* 主料
*/
this.food = foodBuilder.food;
}
大功告成
public class Dishes {
/**
* 调味料
*/
private String condiment;
/**
* 主料
*/
private String food;
@Override
public String toString() {
return "Dishes{" + "condiment='" + condiment + ''' + ", food='" + food + ''' + '}';
}
private Dishes(FoodBuilder foodBuilder) {
/**
* 调味料
*/
this.condiment = foodBuilder.condiment;
/**
* 主料
*/
this.food = foodBuilder.food;
}
/**
* 静态内部类
*/
public static class FoodBuilder {
/**
* 调味料
*/
private String condiment;
/**
* 主料
*/
private String food;
public FoodBuilder buildCondiment(String condiment) {
this.condiment = condiment;
return this;
}
public FoodBuilder buildFood(String food) {
this.food = food;
return this;
}
public Dishes build() {
return new Dishes(this);
}
}
}
宁为代码熬通宵,不让bug点提交,养成良好的单测搞起来
public class Test {
public static void main(String[] args) {
Dishes dishes = new Dishes.FoodBuilder().buildFood("猪肉").buildCondiment("辣椒").build();
System.out.println(dishes);
}
}
Dishes{condiment='辣椒', food='猪肉'}
Process finished with exit code 0
ok,非常 nice,辣椒炒肉做好了
框架运用
建造者模式在框架中的运用非常广泛,我们经常使用的 lombok ,StringBulider 都是建造者模式的实践
lombok
@Data
@Builder
public class User {
private Long id;
private String name;
}
public class TestLombok {
public static void main(String[] args) {
User user = User.builder().id(1L).build();
System.out.println(user);
}
}
StringBulider
StringBulider 中也是非常经典的建造者模式的实现,我们可以聚焦到 129 -138 行
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
我们可以清楚看到 append 方法返回的是 StringBuilder 这个类
当然还有许多框架中藏着建造者模式的影子
Spring 中的建造者模式有
-
BeanDefinitionBuilder -
UriComponents
Mybatis中的
-
SqlSessionFactoryBuilder -
mybatis gennerator生成的Example对象
大家都可以去研究一下 🧐
那么本期就到此结束了。
谨思慎言,我是 Skow 点个赞再走吧,我们下期再见
工厂设计模式,这几个问题你知道吗?
你被空指针折磨过吗?
从一次线上事故聊到类加载机制
原文始发于微信公众号(Issues):10分钟搞懂建造者模式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/107345.html