建造者模式 (Builder Pattern) 属于创建型模式中的一种, 在创建比较复杂的对象, 或者对象包含多个组成部分时比较有用, 用于将对象的创建过程与使用分离, 隔离具体的创建细节, 方便以后的扩展. 它的使用场景包括:
对象的创建比较复杂, 需要进行许多处理工作
对象包含多个组成部分, 而这几个部分之间常常会有较为固定的顺序
创建对象需要许多参数, 会导致构建时的参数列表过长, 难以理解和维护
本文将以一个具体的例子作为引子, 通过对比的形式讲解建造者模式的优点, 最后引入定义和类图.
2. 案例分析
这里以做菜为例子, 通常做菜的步骤包括: 放油, 放葱姜蒜, 加肉, 翻炒, 加盐, 继续翻炒, 装盘, 那么做一份豆角炒肉代码可以这样写:
- public class SimpleCook {
- public static void main(String[] args) {
- SimpleCook cook = new SimpleCook();
- cook.cookmeatWithBeans();
- }
- public void cookmeatWithBeans(){
- System.out.println("热锅下油...");
- System.out.println("加肉...");
- System.out.println("加入葱姜蒜...");
- System.out.println("放入豆角...");
- System.out.println("翻炒均匀...");
- System.out.println("加盐, 继续翻炒...");
- System.out.println("出锅...");
- }
- }
OK, 一盘香喷喷的豆角炒肉就做好了. 不过, 上面的代码还有一些问题:1代码将每个步骤一笔带过, 实际上每一步都会有许多细节, 比如第一步下油, 什么时候倒油, 倒多少合适? 如果把这些详细步骤全部写在一起, 各个步骤之间不仅耦合严重, 而且代码还会显得杂乱, 一旦某个步骤需要改善, 整个方法都受影响;2扩展性问题, 如果我想换个藕丁炒肉, 那就需要新添加一个方法, 没有扩展性. 而且我们会发现豆角炒肉和藕丁炒肉所有的步骤都一样, 只是把 "放入豆角" 改成了 "放入藕丁", 随着类型菜品的增多, 系统会充斥大量的冗余代码.
因此, 这里需要将每个步骤单独提出来作为一个方法, 炒菜的步骤修改之后如下:
- public class SimpleCook {
- public static void main(String[] args) {
- SimpleCook cook = new SimpleCook();
- cook.cookMeatWithBeansBetterWay();
- }
- public void cookMeatWithBeansBetterWay(){
- addOil();
- addMeat();
- addIngredients();
- addDish();
- cookForAWhile();
- addSalt();
- finish();
- }
- private void finish() {
- System.out.println("出锅...");
- }
- private void addSalt() {
- System.out.println("加盐, 继续翻炒...");
- }
- private void cookForAWhile() {
- System.out.println("翻炒均匀...");
- }
- private void addDish() {
- System.out.println("放入豆角...");
- }
- private void addIngredients() {
- System.out.println("加入葱姜蒜...");
- }
- private void addMeat() {
- System.out.println("加肉...");
- }
- private void addOil() {
- System.out.println("热锅下油...");
- }
- }
由于很多菜品都遵循类似的步骤, 只是具体实现不一样, 那么就可以抽象出一个父类, 然后具体的步骤交给子类去实现, 对于其中共同的部分, 可以在抽象父类中提供默认实现:
- public abstract class Builder {
- public abstract void addOil();
- public abstract void addMeat();
- public abstract void addIngredients();
- public abstract void addDish();
- public void cookForAWhile(){
- System.out.println("翻炒均匀...");
- }
- public abstract void addSalt();
- public void finish(){
- System.out.println("出锅...");
- }
- }
抽象父类提供了两个方法的默认实现, 其他的交给子类去处理, 下面是藕丁炒肉子类的实现, 豆角炒肉与此类似:
- public class MeatWithLotusRootBuilder extends Builder{
- @Override
- public void addOil() {
- System.out.println("热锅下油...");
- }
- @Override
- public void addMeat() {
- System.out.println("加肉...");
- }
- @Override
- public void addIngredients() {
- System.out.println("加入葱姜蒜...");
- }
- @Override
- public void addDish() {
- System.out.println("放入藕丁...");
- }
- @Override
- public void addSalt() {
- System.out.println("加盐, 继续翻炒...");
- }
- }
现在, 就可以按照开始规定的步骤炒菜了, 这里, 我们将炒菜的流程放在 Director 中, 由该类管理具体的步骤顺序:
- public class Director {
- Builder builder;
- public Director(Builder builder){
- this.builder = builder;
- }
- public void cook(){
- builder.addOil();
- builder.addIngredients();
- builder.addMeat();
- builder.addDish();
- builder.cookForAWhile();
- builder.addSalt();
- builder.finish();
- }
- }
当我们需要点餐时, 只需要告诉 Director 菜品的名字就可以了, 菜就会按照流程做出来:
- // 客户端代码
- public class BuilderCook {
- public static void main(String[] args) {
- Builder builder = new MeatWithLotusRootBuilder();
- Director director = new Director(builder);
- director.cook();
- }
- }
输出为:
热锅下油...
加入葱姜蒜...
加肉...
放入藕丁...
翻炒均匀...
加盐, 继续翻炒...
出锅...
相比最开始的炒菜方法, 改进之后增加了 Director,Builder,Builder 子类, Director 类规定了创建对象的顺序, Builder 抽象了炒菜的一般步骤, Builder 子类则对应每种菜品的具体实现.
3. 模式类图与定义
根据上面的代码, 总结出建造者模式的类结构如下:
其一般定义为:
建造者模式: 将一个复杂对象的构建与它的表示相分离, 使得同样的构建过程可以创建不同的表示.
4. 常见用法
工作中, 建造者模式更常见的使用场景是对象要设置的参数过多的情况, 例如, 将人抽象为一个 Person 类, 创建的时候需要传递许多信息, 可以使用各种 setter 方法, 但是 Builder 模式能够让这种写法更优雅, 代码如下:
- public class Person {
- String name;
- int age;
- double height;
- double weight;
- String sex;
- // 省略其他字段
- public static void main(String[] args) {
- Person person =
- new Builder().name("zhang san")
- .age(20).height(174)
- .weight(130)
- .sex("male")
- .build();
- }
- public Person(Builder builder){
- this.age = builder.age;
- this.height = builder.height;
- this.weight = builder.weight;
- this.name = builder.name;
- this.sex = builder.sex;
- }
- public static class Builder{
- String name;
- int age;
- double height;
- double weight;
- String sex;
- public Builder age(int age){
- this.age = age;
- return this;
- }
- public Builder height(double height){
- this.height = height;
- return this;
- }
- public Builder weight(double weight){
- this.weight = weight;
- return this;
- }
- public Builder name(String name){
- this.name = name;
- return this;
- }
- public Builder sex(String sex){
- this.sex = sex;
- return this;
- }
- public Person build(){
- return new Person(this);
- }
- }
- }
5. 参考
<<大话设计模式>>
一篇文章就彻底弄懂建造者模式(Builder Pattern) https://www.jianshu.com/p/3d1c9ffb0a28
来源: https://www.cnblogs.com/NaLanZiYi-LinEr/p/11825550.html