先说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,当然封装得不彻底,不过能达到我最初想要的链式编程目的,后面如果深入的话,希望能封装得更彻底,更好。