试想一种需求,有一个简单的Bean类,Bean类里有10个属性,但是我们初始化的时候仅仅想设置2个属性,可能会想到构造函数,但是如果需求升级,让我们设置4个,6个属性,如果用构造函数那代码会过于臃肿,此外频繁的set设置属性,调用的地方代码也比较多且可读性不太好,在这时候可以采用构建者模式了。
建造者模式的定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
经典构建者模式有以下几个角色:
构建者角色、指导者、产品角色。
构建者模式的优缺点:
在创建者模式中,客户端不再负责对象的创建与组装,而是把这个对象创建的责任交给其具体的创建者类,把组装的责任交给组装类,客户端只负责对象的调用,从而明确了各个类的职责。
虽然利用创建者模式可以创建出不同类型的产品,但是如果产品之间的差异巨大,则需要编写多个创建者类才能实现,如果这是结合工厂模式更好。
我们以汉堡包为例,通过代码说下构建者模式:
1.产品抽象角色:
/**
* 经典构建者模式-产品抽象角色
* Created by wangmaobo on 2019/3/25.
*/
public abstract class HamBurg {
protected String bread;
protected String vegetable;
protected float prize;
public void setBread(String name) {
this.bread = name;
}
public abstract void setPrize();
public void setVegetable(String vegetable) {
this.vegetable = vegetable;
}
@Override
public String toString() {
return "HamBurg{" +
"bread='" + bread + '\'' +
", vegetable='" + vegetable + '\'' +
", prize='" + prize + '\'' +
'}';
}
}
2.产品具体角色:
/**
* 经典构建者模式-具体构建者类
* Created by wangmaobo on 2019/3/25.
*/
public class ChineseHamBugeBuilder extends Builder {
private HamBurg mHamBurg = new ChineseHamBurg();
@Override
public void buildBread(String bread) {
mHamBurg.setBread(bread);
}
@Override
public void buildVegetable(String vegetable) {
mHamBurg.setVegetable(vegetable);
}
@Override
public void buildPrize() {
mHamBurg.setPrize();
}
@Override
public HamBurg create() {
return mHamBurg;
}
}
3.抽象构建者角色:
/**
* 经典构建者模式-抽象构建者类
* Created by wangmaobo on 2019/3/25.
*/
public abstract class Builder {
public abstract void buildBread(String bread);
public abstract void buildVegetable(String vegetable);
public abstract void buildPrize();
public abstract HamBurg create();
}
4.具体构建者角色:
/**
* 经典构建者模式-具体构建者类
* Created by wangmaobo on 2019/3/25.
*/
public class ChineseHamBugeBuilder extends Builder {
private HamBurg mHamBurg = new ChineseHamBurg();
@Override
public void buildBread(String bread) {
mHamBurg.setBread(bread);
}
@Override
public void buildVegetable(String vegetable) {
mHamBurg.setVegetable(vegetable);
}
@Override
public void buildPrize() {
mHamBurg.setPrize();
}
@Override
public HamBurg create() {
return mHamBurg;
}
}
5.导演角色:
/**
* 经典构建者模式-导演组装类
* Created by wangmaobo on 2019/3/25.
*/
public class Director {
Builder mBuilder;
public Director(Builder builder) {
mBuilder = builder;
}
public Builder construct(String bread, String vegetable) {
mBuilder.buildBread(bread);
mBuilder.buildVegetable(vegetable);
mBuilder.buildPrize();
return mBuilder;
}
}
调用:
Builder builder = new ChineseHamBugeBuilder();
Director director = new Director(builder);
director.construct("chinese bread", "carrot");
HamBurg hamBurg = builder.create();
Log.e("classic hamburg", "中国汉堡包信息:" + hamBurg.toString());
实际上,我们可以将经典构建者模式进行适当调整,在没有批量处理的需求下,调用更加方便。
将构建者角色类稍加改进:
/**
* 经典构建者模式-具体构建者类
* Created by wangmaobo on 2019/3/25.
*/
public class ChineseHamBugeBuilder extends Builder {
private HamBurg mHamBurg = new ChineseHamBurg();
@Override
public Builder buildBread(String bread) {
mHamBurg.setBread(bread);
return this;
}
@Override
public Builder buildVegetable(String vegetable) {
mHamBurg.setVegetable(vegetable);
return this;
}
@Override
public Builder buildPrize() {
mHamBurg.setPrize();
return this;
}
@Override
public HamBurg create() {
return mHamBurg;
}
}
调用:
HamBurg hamBurg1 = new ChineseHamBugeBuilder()
.buildBread("chinese bread")
.buildVegetable("carrot")
.buildPrize()
.create();
Log.e("improve hamburg", "中国汉堡" + hamBurg1.toString());
实际上我们还可以省去抽象类,及导演类,将构建者Builder类作为产品的内部类,类似实现的比如开源框架Retrofit,具体调用:
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.addInterceptor(interceptor);
OkHttpClient client = builder.build();
retrofitInstance = new Retrofit.Builder()
.baseUrl(BASEURL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
当然实际项目开发中我们甚至可以省略构建者角色,参考RxJava的链式调用风格,将所需要的属性设置直接放到产品角色类里面,比如之前我封装过的万能适配器的ViewHolder类:
public class ViewHolder extends RecyclerView.ViewHolder {
private final SparseArray<View> mViews;
private View itemView;
public ViewHolder(View itemView) {
super(itemView);
mViews = new SparseArray<>();
this.itemView = itemView;
this.itemView.setOnClickListener(v -> {
onItemClick(getAdapterPosition());
if (mOnItemClickListener != null)
setOnItemClick(v, getAdapterPosition());
});
setTextChangedListener(this, itemView);
setRatingBarListener(this, itemView);
}
public <T extends View> T getView(int viewId) {
View view = mViews.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
public ViewHolder setText(int viewId, String text) {
if (TextUtils.isEmpty(text)) {
text = "";
}
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
/**
* 如果text为空,显示“--”
*
* @param viewId
* @param text
* @return
*/
public ViewHolder setTextNotNull(int viewId, String text) {
if (TextUtils.isEmpty(text)) {
text = "--";
}
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
public ViewHolder setTextHint(int viewId, String hint) {
if (TextUtils.isEmpty(hint)) {
return this;
}
TextView tv = getView(viewId);
tv.setHint(hint);
return this;
}
public ViewHolder setBackground(int viewId, int drawableId) {
View view = getView(viewId);
view.setBackground(mContext.getResources().getDrawable(drawableId));
return this;
}
/**
* 如果text为空,控件隐藏
*
* @param viewId
* @param text
* @return
*/
public ViewHolder setTextAndView(int viewId, String text) {
TextView tv = getView(viewId);
if (TextUtils.isEmpty(text)) {
tv.setVisibility(View.GONE);
} else {
tv.setText(text);
tv.setVisibility(View.VISIBLE);
}
return this;
}
public ViewHolder setProjectName(int viewId, String text) {
TextView tv = getView(viewId);
if (CommonUtils.IsNull(Constant.project_id) && !CommonUtils.IsNull(text)) {
tv.setVisibility(View.VISIBLE);
tv.setText(text);
} else {
tv.setVisibility(View.GONE);
}
return this;
}
public ViewHolder setTextColor(int viewId, int textColorId) {
TextView tv = getView(viewId);
tv.setTextColor(textColorId);
return this;
}
public ViewHolder setImage(int viewId, Object params) {
ImageView iv = getView(viewId);
if (params instanceof String) {
//自己写加载图片的逻辑-默认的加载模式
GlideUtils.loadImageViewCircle(mContext, params.toString(),
getView(viewId), R.mipmap.image_loading_icon);
} else if (params instanceof Integer) {
iv.setImageResource((int) params);
} else if (params instanceof Bitmap) {
iv.setImageBitmap((Bitmap) params);
} else if (params instanceof Drawable) {
iv.setImageDrawable((Drawable) params);
} else {
try {
throw new Exception("params is wrong!");
} catch (Exception e) {
e.printStackTrace();
}
}
return this;
}
public ViewHolder setCircleImage(int viewId, String url, String name) {
GlideUtils.loadHeadImg(mContext, url, name, getView(viewId));
return this;
}
public ViewHolder setClickListener(int viewId) {
View v = getView(viewId);
v.setOnClickListener(v1 -> onSingleViewClick(v1, getAdapterPosition()));
return this;
}
public ViewHolder setVisible(int viewId) {
View v = getView(viewId);
v.setVisibility(View.VISIBLE);
return this;
}
public ViewHolder setInVisible(int viewId) {
View v = getView(viewId);
v.setVisibility(View.GONE);
return this;
}
public int getCurrentPosition() {
return getAdapterPosition();
}
}
调用举例:
holder.setTextNotNull(R.id.tv_introduce, content.eventTitle)
.setTextNotNull(R.id.tv_urgency, content.urgentName)
.setTextNotNull(R.id.tv_question, content.eventDescribe)
.setTextNotNull(R.id.tv_createPerson, "创建人")
.setTextNotNull(R.id.tv_createTime, create_time)
.setTextNotNull(R.id.tv_startTime, start_time)
.setTextNotNull(R.id.tv_endTime, end_time)
.setTextNotNull(R.id.tv_notice, content.eventStateName)
.setTextNotNull(R.id.tv_work_type, content.eventSourceName);
项目中能用到此模式的地方举例:
1.自定义View里,可以选择性的组装View的属性,避免了各种构造函数的创建;
2.各种Bean类里,比如EventBusBean,数据Bean类;
3.实现某一个大的功能的框架。
ps:开发模式是死的,人是活的,任何一种设计模式都有其优缺点,我们可以根据自己的产品需求,获取其优点,让开发效率及代码可读性更高一点,尽可能“取其精华,去其糟粕”。 |