前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简易理解设计模式之:建造者模式——学习使用“链式调用”

简易理解设计模式之:建造者模式——学习使用“链式调用”

作者头像
Twcat_tree
发布2022-11-30 16:32:24
5490
发布2022-11-30 16:32:24
举报
文章被收录于专栏:二猫の家
介绍:

建造者模式属于创建型模式。将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

类图:

Product(产品类):需要被构建的复杂对象

Builder(抽象建造者):规范产品的组建,一般是由子类实现具体的组件过程

ConcreteBuilder(具体建造者):实现抽象接口,构建复杂对象

Director(指挥者):构造一个使用Builder接口的对象

用法:

• 构建一个非常复杂的对象,如具有很多参数并且都有默认值的时候(代替setter方法构建对象,链式调用代码美观且简洁)

• 相同的方法,不同的执行顺序产生不同的结果时(指挥者中,buildPartA()、buildPartB()、buildPartC()的顺序不同,可能会产生不同的结果)

• 不同配置的构建对象,产生不同结果时(用不同的ConcreteBuilder构建对象,会产生不同的结果)

个人理解:

这个模式比较多用于链式调用分步组装对象,本质还是为了创建对象了。而它最大的特点在于创建的过程中的分步装配具有很大灵活性。如果一个对象灵活性要求比较高的话可以考虑使用此模式,否则可以考虑其它创建型模式。

例子:

在这个模式我觉得最大区别于其它创建型模式的特点就是链式调用和多变的构造方法,为了更简单理解,首先带大家从传统的方法去实现一个简易计数器说明这个模式的用法,然后再用一个大众化的例子去创建一个UI控件。

需求1:实现一个具有加减乘除的简易计算器。

需求2:实现一个复杂UI控件。

1、实现一个计算器

1.1、实现一个产品类

代码语言:javascript
复制
   private int reult = 0;

为了强化此模式中的多变的构造方法特点,我们直接去掉产品类。计算器最终是得到一个经过一系列复杂运算的数,就是得到一个数。这个数就是我们的产品。

1.2、实现一个Builder类

代码语言:javascript
复制
public abstract class Builder {

    public abstract void add(int val);

    public abstract void substract(int val);

    public abstract void multiply(int val);

    public abstract void divide(int val);

    public abstract int getResult();

}

Builder类规范了计算器最终的结果是由加减乘除相关方法造成的。

1.3、实现ConcreteBuilder类

代码语言:javascript
复制
public class Math1Builder extends Builder {

    private int reult = 0;

    @Override
    public void add(int val) {
        reult += val;
    }

    @Override
    public void substract(int val) {
        reult -= val;
    }

    @Override
    public void multiply(int val) {
        reult *= val;
    }

    @Override
    public void divide(int val) {
        reult /= val;
    }

    @Override
    public int getResult() {
        return reult;
    }
}

好的,我们处理一下计算逻辑,Math1Builder是直接将入参运用到四则运算中。如果还有其它算法例如是入参的两倍等,可以新建一个Math2Builder然后类似这样写:

代码语言:javascript
复制
    @Override
    public void add(int val) {
        result += val * val;
    }

总之,这个计算器是怎么算是我们定好的。

1.4、实现一个Director类

代码语言:javascript
复制
public class Director {
    private Builder mBuilder;

    public Director(Builder builder){
        this.mBuilder = builder;
    }

    //构建对象
    public void create(int num1,int num2,int num3,int num4){
        mBuilder.add(num1);
        mBuilder.substract(num2);
        mBuilder.multiply(num3);
        mBuilder.divide(num4);
    }
}

Director中的Create方法控制了构建过程:按顺序做加减乘除。

1.5、实现结果

代码语言:javascript
复制
    public static void main(String[] args) {
        Builder builder = new Math1Builder();

        Director director = new Director(builder);
        director.create(3,2,4,2);
        System.out.println("输出一个数:"+builder.getResult());
    }
代码语言:javascript
复制
输出一个数:2

这个模式传统的做法就是这样实现了,我们分析一下:

• 最终得到的计算结果,就是我们的Product类。

• Builder类接受入参,实现加减乘除的运算逻辑,从而构建Product类。

• Director类控制加减乘除的运算顺序和运算次数,从而控制Builder类的运算逻辑。

在这过程中,每一步的调用次数、调用顺序都可能会影响最终的运算结果,所以算法是多变的。

1.6、通过链式调用优化

在实际开发中,我们会忽略掉Director角色。直接使用Builder来对对象进行组装。具体使用时在每个组件装配的过程中都返回自身,实现链式调用。先看看代码:

代码语言:javascript
复制
public class Builder {

    private int result = 0;

    public Builder add(int val) {
        result += val;
        return this;
    }

    public Builder substract(int val) {
        result -= val;
        return this;
    }

    public Builder multiply(int val) {
        result *= val;
        return this;
    }

    public Builder divide(int val) {
        result /= val;
        return this;
    }

    public int getResult() {
        return result;
    }
}

在这个例子中,Director、Builder、甚至是Product类都直接省略掉了,只剩下一个ConcreteBuilder。这样调用更加灵活:

代码语言:javascript
复制
public static void main(String[] args) {
    int result = new Builder().add(3).substract(2).multiply(4).divide(2).add(3).getResult();
    System.out.println("输出一个数:" + result);
}
代码语言:javascript
复制
输出一个数:5

我们清楚了解到链式调用就是建造者模式的一个重要特点。

2、实现一个UI控件

此模式常用于构建复杂对象,例如Android中UI控件使用此模式后能简化使用,很值得我们参考。

如比较著名的Glide框架:

代码语言:javascript
复制
Glide.with(Context context).load(Strint url).into(ImageView imageView);

AlertDialog.Builder:

代码语言:javascript
复制
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setIcon(R.drawable.icon);
        builder.setTitle("标题");
        builder.setMessage("信息");
        builder.setPositiveButton("确定",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });
        AlertDialog alertDialog = builder.create();
        alertDialog.show();

2.1、用伪代码实现AlertDialog.Builder(非源码)

代码语言:javascript
复制
public class AlertDialog {
    private final int icon;
    private final String message;
    private final String title;
    private final View.OnClickListener listener;

    private AlertDialog(Builder builder) {
        icon = builder.icon;
        message = builder.message;
        title = builder.title;
        listener = builder.listener;
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public static final class Builder {
        private int icon;
        private String message;
        private String title;
        private View.OnClickListener listener;

        private Builder() {
        }

        public Builder icon(int val) {
            icon = val;
            return this;
        }

        public Builder message(String val) {
            message = val;
            return this;
        }

        public Builder title(String val) {
            title = val;
            return this;
        }

        public Builder listener(View.OnClickListener val) {
            listener = val;
            return this;
        }

        public AlertDialog build() {
            return new AlertDialog(this);
        }
    }
}

AlertDialog就是我们的产品类,需要设置各种属性。

AlertDialog.Builder类同时充当Builder、ConcreteBuilder、Director。

2.2、调用

代码语言:javascript
复制
 AlertDialog mDialog = AlertDialog.newBuilder()
         .icon(R.mipmap.ic_launcher)
         .title("标题")
         .message("信息")
         .listener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
             }
         }).build();

这种复杂的构建过程,只需几行简单的代码就把AlertDialog创建出来了。例子2着重于简化创建复杂对象,模式隐藏了这种复杂的构建过程,大家可以尝试理解一下。

总结

• 这个模式的比较多用于通过链式调用分步组装对象,本质还是创建一个对象。

• 在组装的过程中的算法是多变的,每一步的调用次数、调用顺序都可能会影响最终结果。而组件的装配方式是稳定不变的,每个调用算法都是独立影响最终变化的。

感谢您的阅读~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍:
  • 类图:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档