采用Build模式构建自定义Dialog

本文介绍了Build模式的概念,并通过实例展示了如何将一个复杂的Dialog构建过程改造成使用Build模式,以实现链式编程。文章首先展示了一个没有使用Build模式的Dialog写法,然后逐步改进,简化参数传递,提高代码可读性和可维护性。最终,通过示例代码展示了Build模式在自定义Dialog中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先说Build的概念,我看到网上有很多关于这个模式的解释说明,我比较认同的是下面的这种理解:
所谓Build模式就是:一步一步将一个复杂对象创建出来,允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。

我们最深的体会就是链式编程的运用,这里面基本上都是创建了一个内部静态Build. Android中尤为常见,比如说AlertDialog. 我这里就拿自己做的一个Dialog仿照AlertDialog,运用Build模式来创建,可能封装得有些不完整,但是我一开始的目的就是希望能用到链式编程,所以就算不完整,我还是拿来作为案例讲解。

1.效果图:

这里写图片描述

2. 没有运用Build模式的写法:

可以看到这个Dialog中,需要传递的参数非常多,总计有8个,按照普通写法,可能在new Dialog中需要一次性传递8个参数,不要笑话我,我开始赶进度的时候确实是这么做的。

 public EffectDialog(Context context, int themeResId,String effect,String visit,String praise,
                        String comment,String share,String collection,String reward,String speed) {
        super(context, themeResId);
        mEffect = effect;
        mVisit = visit;
        mPraise = praise;
        mComment = comment;
        mShare = share;
        mCollection = collection;
        mReward = reward;
        mSpeed = speed;
    }

然后在调用的地方,使劲的传参数,还时不时看有没有传错位。太痛苦了。
然后痛定思痛,开始改造。

3. 改造成Build模式

先看源码AlertDialog, 有个AlertController

private AlertController mAlert;

还有个内部静态类Builder,我这里只摘抄几个方法:


public static class Builder {

    private final AlertController.AlertParams P;


     public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

    public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }
..........

还有个就是要看AlertDialog的OnCreate方法:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }

从这里,我们就应该可以看出:AlertDialog中需要的成员变量,封装到AlertController中,通过Build设置的参数,都是 赋值给了AlertController.AlertParams P。示意图就是:
AlertDialog《===AlertController《===Build

我不想做那么复杂,就省略掉AlertController, 直接用Dialog和Build类。Build类中赋值都是赋值给Dialog中的成员变量,setView的操作直接交给Dialog自己做,不需要封装到Build类中,示意图为:
EffectDialog <===Build

先看Build能做的事情:设置成员变量的值和一个listener. 仔细看AlertDialog 的Build,里面封装的远远不止这些,在这里我只封装这么多够用了。

 public static class Builder{


        private EffectDialog mDialog;

        public Builder(Context context, int themeResId){
            mDialog = new EffectDialog(context,themeResId);
        }

        public Builder setEffect(String effect){
            mDialog.mEffect = effect;
            return this;
        }

        public Builder setPraise(String praise){
            mDialog.mPraise = praise;
            return this;
        }

        public Builder setVisit(String visit){
            mDialog.mVisit = visit;
            return this;
        }

        public Builder setComment(String comment){
            mDialog.mComment = comment;
            return this;
        }

        public Builder setShare(String share){
            mDialog.mShare = share;
            return this;
        }

        public Builder setCollection(String collection){
            mDialog.mCollection = collection;
            return this;
        }

        public Builder setReward(String reward){
            mDialog.mReward = reward;
            return this;
        }

        public Builder setSpeed(String speed){
            mDialog.mSpeed = speed;
            return this;
        }

        public Builder setOnMyShareListener(MyShareListener listener){
            mDialog.myListener= listener;
            return this;
        }

        public EffectDialog createDialog(){
            return mDialog;
        }

    }

再看Dialog自己能做的事情:setContentView(), 这个可以交给Build做,但是我觉得用Dialog自己处理比较好,就没有封装到Build类中了。还有一个就是自己定义的接口MyShareListener,刚开始也是交给Dialog自己做,但是看到AlerDialog中也是交给了Build,所以也模仿了一次,交给了Builder。

public class EffectDialog extends Dialog implements View.OnClickListener{


private TextView mTvEffect;//影响因子
private TextView mTvVisit;//浏览量
private TextView mTvPraise;//点赞数
private TextView mTvComment;//评论数
private TextView mTvshare;//分享数
private TextView mTvCollection;//收藏数
private TextView mTvReward;//打赏人次
private TextView mTvSpeed;//首次阅读速度
private Button mBtnShare;//分享出去
private ImageView mIvClose;//关闭


private String mEffect;
private String mVisit;
private String mPraise;
private String mComment;
private String mShare;
private String mCollection;
private String mReward;
private String mSpeed;

private  MyShareListener myListener;

 public EffectDialog(Context context, int themeResId) {
        super(context, themeResId);

    }



 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_effect);
        initView();
        setClickListener();
    }



private void initView() {
        mTvEffect = (TextView) findViewById(R.id.tv_effect);
        mTvVisit = (TextView) findViewById(R.id.tv_visit);
        mTvPraise = (TextView) findViewById(R.id.tv_praise);
        mTvComment = (TextView) findViewById(R.id.tv_comment);
        mTvshare =(TextView) findViewById(R.id.tv_share);
        mTvCollection = (TextView) findViewById(R.id.tv_collection);
        mTvReward =  (TextView) findViewById(R.id.tv_reward);
        mTvSpeed = (TextView) findViewById(R.id.tv_speed);
        mIvClose = (ImageView) findViewById(R.id.iv_close);
        mBtnShare = (Button) findViewById(R.id.btn_share);

        mTvEffect.setText(mEffect);
        mTvVisit.setText(mVisit);
        mTvPraise.setText(mPraise);
        mTvComment.setText(mComment);
        mTvshare.setText(mShare);
        mTvCollection.setText(mCollection);
        mTvReward.setText(mReward);
        mTvSpeed.setText(mSpeed);

    }

    private void setClickListener() {
        mIvClose.setOnClickListener(this);
        mBtnShare.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.iv_close){
            dismiss();
        }else if(v.getId()==R.id.btn_share){
            if(myListener!=null){
                myListener.onMyShare();
                dismiss();
            }
        }
    }


 public interface MyShareListener {
        void onMyShare();
    }

}

最后再看看如何调用:


/**没有Build模式,用的是这中方法*/
//EffectDialog dialog = new EffectDialog(mContext,R.style.AlertDialogStyle,                           //dataBean.getAFFECT_NUM(),dataBean.getVIEWNUM(),dataBean.getPRAISENUM(),                           //dataBean.getCOMMENTNUM(),dataBean.getSHARENUM(),dataBean.getCOLLECTIONNUM(),
//                            dataBean.getREWARDNUM(),dataBean.getVIEW_SPEED());


/**用了Build模式之后:链式调用*/

EffectDialog dialog = new EffectDialog.Builder(mContext,R.style.AlertDialogStyle)
                            .setVisit(dataBean.getVIEWNUM())
                            .setSpeed(dataBean.getVIEW_SPEED())
                            .setCollection(dataBean.getCOLLECTIONNUM())
                            .setComment(dataBean.getCOMMENTNUM())
                            .setShare(dataBean.getSHARENUM())
                            .setEffect(dataBean.getAFFECT_NUM())
                            .setReward(dataBean.getREWARDNUM())
                            .setPraise(dataBean.getPRAISENUM())
                            .setOnMyShareListener(new EffectDialog.MyShareListener() {
                                @Override
                                public void onMyShare() {
                                    showShareDialog(dataBean);
                                }
                            })
                            .createDialog();
                    dialog.show();
}

好了,以上就是用Build模式写的一个Dialog,当然封装得不彻底,不过能达到我最初想要的链式编程目的,后面如果深入的话,希望能封装得更彻底,更好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值