我们知道,构建java实例有很多方法;最常见的就是通过构造器方式,还有就是前几篇说的静态工厂方法的方式,今天我们就来说一说通过构建器创建java对象的方式。
因为今天我们要介绍通过构建器创建对象,那么它必然为了解决某些问题而出现和存在的,那我们就来看看传统的构造器创建对象会有哪些问题:
public class Television {
private int width;
private int height;
private float weight=0.0f;
private String color="black";
private String brand="panda";
private String serialNum="ID1000";
public Television(int width,int height) {
this.width=width;
this.height=height;
}
public Television(int width,int height,float weight) {
this.width=width;
this.height=height;
this.weight=weight;
}
public Television(int width, int height, float weight, String color, String brand, String serialNum) {
this.width = width;
this.height = height;
this.weight = weight;
this.color = color;
this.brand = brand;
this.serialNum = serialNum;
}
}
我这里的成员变量给的较少,构造器也没有写全。
比如:一个电视机的长,宽,高都是int类型参数,当你调用一个只有长和宽的构造器时把高当中长传进去之后,这样的问题很难排查。
到这里很多人想,这里的难点主要是在成员变量太多的时候,构造器太多;客户端代码编写起来很麻烦而且容易出错,出现错误也不好修改。简单一想,好像我们可以很简单的通过JavaBeans方式来规避这个问题。
- 创建对象都是通过默认无参的构造器或者默认有参的构造器
- 通过setter来设置成员变量的值
这样做,确实有以下优点:
- 容易阅读
- 对象创建简单
比如上述代码就可以修改为:
public class Television {
private int width;
private int height;
private float weight=0.0f;
private String color="black";
private String brand="panda";
private String serialNum="ID1000";
public Television(int width,int height) {
this.width=width;
this.height=height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public float getWeight() {
return weight;
}
public void setWeight(float weight) {
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getSerialNum() {
return serialNum;
}
public void setSerialNum(String serialNum) {
this.serialNum = serialNum;
}
}
这种方式确实解决了构造器调用困难的问题,也更加易于阅读;但是与此同时有产生了新的问题:
Television tv3 = new Television(width, height);
//tv3变化了
tv3.setBrand("nb");
Television tv3 = new Television(width, height);
tv3.setBrand("nb");
tv3.setColor("red");
tv3.setSerialNum("ID1200");
在尝试了使用JavaBeans模式解决出现问题之后,现在就需要一种构建对象的方式满足:
- 达到构造器那样的数据安全性
- 达到JavaBeans模式的可读性和灵活性
答案自然是我们今天要结束的主角构建器,其实使用构建器很简单,关键是是否选择使用它;那么我们就来看看使用它的基本思想和步骤。
- 类中添加一个静态内部类,其中含有和要创建对象的类有一样的参数,还有一系列类似setter功能的方法;保证了灵活性
- 该静态内部类有一个转换本类参数至外部类参数的接口(配合外部类的私有构造器);保证了安全性
- 客户端通过创建内部类来初始化要创建对象的成员变量,然后调用内部类接口获取外部类实例对象
还是上面那一个例子:
package hfut.edu;
/**
* Date:2018年9月25日 下午6:59:23
* Author:why
*/
public class TelevisionWithBuilder {
//the required parameters
private int width;
private int height;
//the optional parameters
private float weight;
private String color;
private String brand;
private String serialNum;
//the constructor used for transfer the Builder's parameter to the Object that we want
//to create
private TelevisionWithBuilder(Builder builder) {
this.width=builder.width;
this.height=builder.height;
this.weight=builder.weight;
this.color=builder.color;
this.brand=builder.brand;
this.serialNum=builder.serialNum;
}
public static class Builder{
private int width;
private int height;
private float weight=0.0f;
private String color="black";
private String brand="panda";
private String serialNum="ID1000";
//the default public constructor
public Builder(int width,int height ) {
this.width=width;
this.height=height;
}
//following is the Builder's functional method
public Builder setWeight(float weight) {
this.weight=weight;
return this;
}
public Builder setColor(String color) {
this.color=color;
return this;
}
public Builder setBrand(String brand) {
this.brand=brand;
return this;
}
public Builder setSerialNum(String serialNum) {
this.serialNum=serialNum;
return this;
}
//use the private constructor to build the project
public TelevisionWithBuilder build() {
return new TelevisionWithBuilder(this);
}
}
@Override
public String toString() {
return "TelevisionWithBuilder [width=" + width + ", height=" + height + ", weight=" + weight + ", color="
+ color + ", brand=" + brand + ", serialNum=" + serialNum + "]";
}
}
代码里很明朗:
其中在Android中有不少构建器的例子,很多的开源框架也都有使用到,今天就简单介绍一下Android中的AlertDialog的构建器
首先简单看一下AlertDialog的API部分介绍:
嵌套类摘要 | |
---|---|
static class |
AlertDialog.Builder |
AlertDialog.Builder的API部分介绍:
方法摘要 | |
---|---|
AlertDialog |
create() Creates a AlertDialog with the arguments supplied to this builder. |
AlertDialog.Builder |
setAdapter(ListAdapter adapter, DialogInterface.OnClickListener listener) Set a list of items, which are supplied by the given ListAdapter , to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setCancelable(boolean cancelable) Sets whether the dialog is cancelable or not default is true. |
AlertDialog.Builder |
setCursor(Cursor cursor, DialogInterface.OnClickListener listener, String labelColumn) Set a list of items, which are supplied by the given Cursor , to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setCustomTitle(View customTitleView) Set the title using the custom view customTitleView . |
AlertDialog.Builder |
setIcon(Drawable icon) Set the Drawable to be used in the title. |
AlertDialog.Builder |
setIcon(int iconId) Set the resource id of the Drawable to be used in the title. |
AlertDialog.Builder |
setInverseBackgroundForced(boolean useInverseBackground) Sets the Dialog to use the inverse background, regardless of what the contents is. |
AlertDialog.Builder |
setItems(CharSequence[] items, DialogInterface.OnClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setItems(int itemsId, DialogInterface.OnClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setMessage(CharSequence message) Set the message to display. |
AlertDialog.Builder |
setMessage(int messageId) Set the message to display using the given resource id. |
AlertDialog.Builder |
setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, DialogInterface.OnMultiChoiceClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setMultiChoiceItems(int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) Set a listener to be invoked when the negative button of the dialog is pressed. |
AlertDialog.Builder |
setNegativeButton(int textId, DialogInterface.OnClickListener listener) Set a listener to be invoked when the negative button of the dialog is pressed. |
AlertDialog.Builder |
setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) Set a listener to be invoked when the neutral button of the dialog is pressed. |
AlertDialog.Builder |
setNeutralButton(int textId, DialogInterface.OnClickListener listener) Set a listener to be invoked when the neutral button of the dialog is pressed. |
AlertDialog.Builder |
setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) Sets the callback that will be called if the dialog is canceled. |
AlertDialog.Builder |
setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) Sets a listener to be invoked when an item in the list is selected. |
AlertDialog.Builder |
setOnKeyListener(DialogInterface.OnKeyListener onKeyListener) Sets the callback that will be called if a key is dispatched to the dialog. |
AlertDialog.Builder |
setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) Set a listener to be invoked when the positive button of the dialog is pressed. |
AlertDialog.Builder |
setPositiveButton(int textId, DialogInterface.OnClickListener listener) Set a listener to be invoked when the positive button of the dialog is pressed. |
AlertDialog.Builder |
setRecycleOnMeasureEnabled(boolean enabled) |
AlertDialog.Builder |
setSingleChoiceItems(CharSequence[] items, int checkedItem, DialogInterface.OnClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, DialogInterface.OnClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setSingleChoiceItems(int itemsId, int checkedItem, DialogInterface.OnClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setSingleChoiceItems(ListAdapter adapter, int checkedItem, DialogInterface.OnClickListener listener) Set a list of items to be displayed in the dialog as the content, you will be notified of the selected item via the supplied listener. |
AlertDialog.Builder |
setTitle(CharSequence title) Set the title displayed in the Dialog . |
AlertDialog.Builder |
setTitle(int titleId) Set the title using the given resource id. |
AlertDialog.Builder |
setView(View view) Set a custom view to be the contents of the Dialog. |
AlertDialog.Builder |
setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom) Set a custom view to be the contents of the Dialog, specifying the spacing to appear around that view. |
AlertDialog |
show() Creates a AlertDialog with the arguments supplied to this builder and Dialog.show() 's the dialog. |
从API不难看出,它和我们上面分析的都是大同小异,下面就来看看这个AlertDialog.Builder是如何创建AlertDialog的:
/**
* Creates an {@link AlertDialog} with the arguments supplied to this
* builder.
*
* Calling this method does not display the dialog. If no additional
* processing is needed, {@link #show()} may be called instead to both
* create and display the dialog.
*/
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;
}
这里面的P你可以理解为一个用于保存通过Builder中属性方法设置的属性值的一个实体,其类型为:
AlertController.AlertParams
暂时也不需要纠结太深入的去理解;我们可以简单看一个例子就明白了,比如,我们想设置AlertDialog的Title,首先通过设置到该属性值到AlertDialog.Builder中的用于保存这些参数值的P中,然后通过create方法把AlertDialog.Builder中的P的参数转给AlertDialog即可;和我们上面的其实是一模一样的。
/**
* Set the title displayed in the {@link Dialog}.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
转至《Effective Java》中文版 第2版:
如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是一种不错的选择;特别是当对象的大多数参数是可选的时候。
关于使用泛型类根据需求使用Builder返回不同的对象,这里就不在举例介绍了。
注:欢迎扫码关注