内容简介:在开发中,经常用到builder设计模式,但感觉最常见的应用场景就是构造对象参数较多的时候,本文将builder模式梳理总结一下。非要给builder模式一个定义,我就查看了《Android源码设计模式解析与实战》,以下是其给出的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
在开发中,经常用到builder设计模式,但感觉最常见的应用场景就是构造对象参数较多的时候,本文将builder模式梳理总结一下。
定义
非要给builder模式一个定义,我就查看了《Android源码 设计模式 解析与实战》,以下是其给出的定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
这样的总结比较经典,但是感觉离彻底明白其中的含义还差点距离。前半句可以理解为将一个对象的创建过程分多步,后半句可以这样理解,使用同样的构建过程,传递不同的参数会产生不同的结果。
经典写法
上图为builder经典写法的uml,其实在实际开发过程中,Director部分经常就被去掉了。 如下所示,定义了AbstractBuilder:
public abstract class AbstractBuilder { public abstract void buildPart1(int numOfWheel); public abstract void buildPart2(int numOfSeat); public abstract void buildPart3(int capacity); public abstract Vehicle build(); } 复制代码
demo的目标是将车辆Vehicle的构建分离,demo中的Product为Vehicle类型,可以看下Vehicle的定义:
public abstract class Vehicle { // 车轮的数量 protected int numOfWheel; // 座椅的数量 protected int numOfSeat; // 载重,car按照人数,truck按照吨数 protected int capacity; public void setNumOfWheel(int numOfWheel) { this.numOfWheel = numOfWheel; } public void setNumOfSeat(int numOfSeat) { this.numOfSeat = numOfSeat; } public abstract void setCapacity(int capacity); } 复制代码
demo中Vehicle的子类有Car(小轿车)和Truck(卡车),Car类的定义如下:
public class Car extends Vehicle { @Override public void setCapacity(int capacity) { // TODO Auto-generated method stub super.capacity = capacity; } @Override public String toString() { // TODO Auto-generated method stub return "car parameter:" + numOfWheel + "-" + numOfSeat + "-" + capacity; } } 复制代码
Truck的定义如下:
public class Truck extends Vehicle { @Override public void setCapacity(int capacity) { // TODO Auto-generated method stub super.capacity = capacity; } @Override public String toString() { // TODO Auto-generated method stub return "car parameter:" + numOfWheel + "-" + numOfSeat + "-" + capacity + " ton"; } } 复制代码
接下来就看下Car的builder CarBuilder:
public class CarBuilder extends AbstractBuilder { private Car car = new Car(); @Override public void buildPart1(int numOfWheel) { // TODO Auto-generated method stub car.setNumOfWheel(numOfWheel); } @Override public void buildPart2(int numOfSeat) { // TODO Auto-generated method stub car.setNumOfSeat(numOfSeat); } public void buildPart3(int capacity) { // TODO Auto-generated method stub car.setCapacity(capacity); } public Vehicle build() { return car; } } 复制代码
TruckBuilder定义如下:
public class TruckBuilder extends AbstractBuilder { private Truck truck = new Truck(); @Override public void buildPart1(int numOfWheel) { // TODO Auto-generated method stub truck.setNumOfWheel(numOfWheel); } @Override public void buildPart2(int numOfSeat) { // TODO Auto-generated method stub truck.setNumOfSeat(numOfSeat); } @Override public void buildPart3(int capacity) { // TODO Auto-generated method stub truck.setCapacity(capacity); } @Override public Vehicle build() { // TODO Auto-generated method stub return truck; } } 复制代码
以上定义了CarBuiler, TruckBuiler。虽然在实际开发中经常会省略掉Director部分,为了演示,demo也定义了Director
public class Director { private AbstractBuilder builder; public Director(AbstractBuilder builder) { this.builder = builder; } public void construct(int numOfWheel, int numOfSeat, int capacity) { if (builder != null) { builder.buildPart1(numOfWheel); builder.buildPart2(numOfSeat); builder.buildPart3(capacity); } } } 复制代码
OK,所有需要定义的部分已经完成,接下来就去调用一下:
public class Client { public static void main(String [] args) { AbstractBuilder builder = new CarBuilder(); Director director = new Director(builder); director.construct(4, 5, 5); Car car = (Car) builder.build(); System.out.println(car); AbstractBuilder builder2 = new TruckBuilder(); Director director2 = new Director(builder2); director2.construct(8, 2, 5); Truck truck = (Truck) builder2.build(); System.out.println(truck); } } 复制代码
程序输入如下: car parameter:4-5-5 truck parameter:8-2-5 ton
demo演示部分将Vehicle的构造过程分3步,执行完3步构建后返回实例对象。
日常写法
上面的demo是经典的写法,但在实际开发中,很少写的那么标准或者那么复杂,大多数情况下builder模式主要是为了防止在构建对象时传递太多的参数。查看下以下demo:
public class Student { private String name; private String nickName; private String sex; private int age; private int weight; private int height; public Student(String name, String nickName, String sex, int age, int weight, int height) { // TODO Auto-generated constructor stub this.name = name; this.nickName = nickName; this.sex = sex; this.age = age; this.weight = weight; this.height = height; } @Override public String toString() { // TODO Auto-generated method stub return "student info:name=" + name + "\n" + "nickname=" + nickName + "\n" + "sex=" + sex + "\n" + "age=" + age + "\n" + "weight=" + weight + "\n" + "height=" + height; } public static class Builder { private String name; private String nickName; private String sex; private int age; private int weight; private int height; public Builder name(String name) { this.name = name; return this; } public Builder nickName(String nickName) { this.nickName = nickName; return this; } public Builder sex(String sex) { this.sex = sex; return this; } public Builder age(int age) { this.age = age; return this; } public Builder weight(int weight) { this.weight = weight; return this; } public Builder height(int height) { this.height = height; return this; } public Student build() { return new Student(name, nickName, sex, age, weight, height); } } } 复制代码
以下是测试程序:
public class Client { public static void main(String [] args) { Student student = new Student.Builder().name("rock") .nickName("store") .sex("boy") .age(12) .weight(60) .height(176).build(); System.out.println(student); } } 复制代码
程序运行结果如下:
student info:name=rock nickname=store sex=boy age=12 weight=60 height=176 复制代码
Android中Builder使用场景
在开发过程中,经常使用的builder模式其实就是上文所说的日常写法,Android中最常见的builder模式就是AlertDialog的创建过程了,以下是AlertDialog创建过程的常见写法。
AlertDialog.Builder builder = new AlertDialog.Builder(context) .setTitle(title) .setView(view) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .setNegativeButton(android.R.string.cancel, null); builder.create().show(); 复制代码
感觉很熟悉,这就是我们最常用的AlertDialog的构建过程。扒一扒源码,由于AlertDialog.Builder的源码较多,就不全部贴出来,感兴趣的同学可以自行看一下。
public static class Builder { private final AlertController.AlertParams P; public Builder(Context context) { this(context, resolveDialogTheme(context, ResourceId.ID_NULL)); } ...... public Builder setTitle(@StringRes int titleId) { P.mTitle = P.mContext.getText(titleId); return this; } public Builder setTitle(CharSequence title) { P.mTitle = title; return this; } public Builder setCustomTitle(View customTitleView) { P.mCustomTitleView = customTitleView; return this; } ...... public Builder setMessage(CharSequence message) { P.mMessage = message; return this; } public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) { P.mPositiveButtonText = P.mContext.getText(textId); P.mPositiveButtonListener = listener; return this; } ...... public AlertDialog create() { // Context has already been wrapped with the appropriate theme. final AlertDialog dialog = new AlertDialog(P.mContext, 0, false); P.apply(dialog.mAlert); dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.mOnCancelListener); dialog.setOnDismissListener(P.mOnDismissListener); if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } return dialog; } } 复制代码
AlertDialog.Buidler类中定义各种set方法,执行完set方法之后再执行create方法便创建了一个AlertDialog。这应该是一个标准的builder模式了。可以发现AlertDialog.Builder执行set方法,其实就是将set参数复制给了对象P。对象P是什么结构呢?
public static class AlertParams { public final Context mContext; public final LayoutInflater mInflater; public int mIconId = 0; public Drawable mIcon; public int mIconAttrId = 0; public CharSequence mTitle; public View mCustomTitleView; public CharSequence mMessage; public CharSequence mPositiveButtonText; public DialogInterface.OnClickListener mPositiveButtonListener; public CharSequence mNegativeButtonText; public DialogInterface.OnClickListener mNegativeButtonListener; public CharSequence mNeutralButtonText; public DialogInterface.OnClickListener mNeutralButtonListener; public boolean mCancelable; public DialogInterface.OnCancelListener mOnCancelListener; public DialogInterface.OnDismissListener mOnDismissListener; public DialogInterface.OnKeyListener mOnKeyListener; public CharSequence[] mItems; public ListAdapter mAdapter; public DialogInterface.OnClickListener mOnClickListener; public int mViewLayoutResId; public View mView; public int mViewSpacingLeft; public int mViewSpacingTop; public int mViewSpacingRight; public int mViewSpacingBottom; public boolean mViewSpacingSpecified = false; public boolean[] mCheckedItems; public boolean mIsMultiChoice; public boolean mIsSingleChoice; public int mCheckedItem = -1; public DialogInterface.OnMultiChoiceClickListener mOnCheckboxClickListener; public Cursor mCursor; public String mLabelColumn; public String mIsCheckedColumn; public boolean mForceInverseBackground; public AdapterView.OnItemSelectedListener mOnItemSelectedListener; public OnPrepareListViewListener mOnPrepareListViewListener; public boolean mRecycleOnMeasure = true; ...... } 复制代码
可以发现,AlertController.AlertParams类型的对象P其实就是存放了构建AlertDialog需要的各种参数。对象P中海油其他函数操作,感兴趣的同学可以去看一下。
将参数保存到P对象,然后执行create函数,创建新的AlertDialog对象,然后P中存放的属性设置给新建的AlertDilaog对象,这样,就完成了AlertDialog的构建。
总结
Builder模式的目标是将复杂对象的创建过程进行分解,使对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。在实际开发过程中,通常是在复杂对象内部申明静态内部类Builder,在Builder中保存复杂对象的属性,然后使用create或者build函数将保存的属性设置给对象。
其实日常开发过程中使用builder模式还没有让我们领略到builer模式的强大,建议参考下这篇文章体会一下: www.cnblogs.com/happyhippy/…
以上所述就是小编给大家介绍的《Builder 模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 简单工厂模式、工厂模式、抽象工厂模式的解析-iOS
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
BSD Hacks
Dru Lavigne / O'Reilly Media, Inc. / 2004-05-24 / USD 24.95
If you want more than your average BSD user--you want to explore and experiment, unearth shortcuts, create useful tools, and come up with fun things to try on your own--BSD Hacks is a must-have. This ......一起来看看 《BSD Hacks》 这本书的介绍吧!