一 Builder模式介绍及使用场景
Builder模式是一步一步创建一个复杂对象的创建者模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。该模式是为了将复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。
因为一个复杂的对象有很多大量组成部分,如汽车,有车轮、方向盘、发动机,还有各种小零件,如何将这件部件装配成一辆汽车,这个装配过程很漫长,也很复杂,对于这种情况,为了在构建过程中对外部隐藏实现细节,也可以使用Builder模式将部件和组装过程分离,使得构建过程和部件都可以自有拓展,两者之间的耦合也降到最低。
在项目中最常见到的两个使用Builder模式的案例,一个是AlertDialog.Builder的创建,另一个就是著名的图片加载框架ImageLoader的初始配置。
ImageLoader的初始配置如下:
ImageLoaderConfiguration config = new ImageLoaderConfiguration
.Builder(context)
.memoryCacheExtraOptions(480, 800) // max width, max height,即保存的每个缓存文件的最大长宽
.discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null) // Can slow ImageLoader, use it carefully (Better don't use it)/设置缓存的详细信息,最好不要设置这个
.threadPoolSize(3)//线程池内加载的数量
.threadPriority(Thread.NORM_PRIORITY - 2)
.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) // You can pass your own memory cache implementation/你可以通过自己的内存缓存实现
.memoryCacheSize(2 * 1024 * 1024) //设置内存缓存的大小
.discCacheSize(50 * 1024 * 1024) //设置磁盘缓存的大小
.discCacheFileNameGenerator(new Md5FileNameGenerator())//将保存的时候的URI名称用MD5 加密
.discCacheFileCount(100) //缓存的文件数量
.discCache(new UnlimitedDiscCache(cacheDir))//自定义缓存路径
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.imageDownloader(new BaseImageDownloader(context, 5 * 1000, 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)超时时间
.writeDebugLogs() // Remove for release app
.build();//开始构建
//然后
ImageLoader.getInstance().init(config);//全局初始化此配置
Builder模式的使用场景:
(1)多个部件或零件,不同的执行顺序,产生不同的事件结果时;
(2)多个部件或者零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
(3)当初始化一个对象特别复杂,参数多,且很多参数都具有默认值。
二 Builder模式的结构图
结构图如下:
角色介绍:
(1)Product:产品的抽象类
(2)Builder:抽象的Builder类,规范产品的组件,一般由子类实现具体的组建过程。
(3)ConcreteBuilder: 具体的Builder类。
(4)Director:统一的组装过程。
三 Builder模式的简单DEMO:
不知道大家有没有自己组装过电脑,组装之前我们都得先购买好电脑的各个部件,比如主板,显示器,内存条等,然后安装相应的操作系统。以电脑Computer的三个部件(主板Board,显示器Display,操作系统OS)表示为例:
//计算机抽象类 即是Product角色
public abstract class Computer {
//含有主板Board,显示器Display,操作系统OS
protected String mBoard;
protected String mDisplay;
protected String mOs;
protected Computer(){};
//设置主板
public void setmBoard(String mBoard) {
this.mBoard = mBoard;
}
//设置显示器
public void setmDisplay(String mDisplay) {
this.mDisplay = mDisplay;
}
//设置操作系统
public abstract void setmOs();
@Override
public String toString() {
return "Computer{" +
"mBoard='" + mBoard + '\'' +
", mDisplay='" + mDisplay + '\'' +
", mOs='" + mOs + '\'' +
'}';
}
}
然后比如我们要装一个MAC的电脑:
//具体的Computer类
public class Macbook extends Computer{
public Macbook(){};
@Override
public void setmOs() {
mOs="MAC OS X 10.10";
}
}
对应的抽象Builder是:
//抽象的Builder类 规范电脑的组装设置
public abstract class Builder {
//设置主机
public abstract void setBoard(String board);
//设置显示器
public abstract void setDisplay(String display);
//设置操作系统
public abstract void setOS();
//创建computer
public abstract Computer create();
}
具体的Builder,实现电脑的组装:
//具体的Builder类
public class MacbookBuilder extends Builder{
private Computer macComputer=new Macbook();
@Override
public void setBoard(String board) {
macComputer.setmBoard(board);//设置主板
}
@Override
public void setDisplay(String display) {
macComputer.setmDisplay(display);//设置显示器
}
@Override
public void setOS() {
macComputer.setmOs();//设置操作系统
}
@Override
public Computer create() {//创建方法
return macComputer;
}
}
客户端实现如下:
Builder macbookBuilder= new MacbookBuilder();
macbookBuilder.setBoard("英特尔主板");
macbookBuilder.setDisplay("三星显示器");
macbookBuilder.setOS();
String tag1=macbookBuilder.create().toString();
Log.i("TAG",tag1);
打印结果如下:
04-16 06:48:45.899 9551-9551/com.troy.builderpattern I/TAG: Computer{mBoard='英特尔主板', mDisplay='三星显示器', mOs='MAC OS X 10.10'}
上述示例中,通过具体的MacbookBuilder来构建了Macbook对象,并且我们忽略了Director的角色,而直接使用一个Builder来进行对象的组装。
以上的写法中,我们当然我们还可以改写Builder的代码,实现Builder的链式调用,类似ImageLoade初始配置那样,一行代码搞定:
new XBuilder().setA("A").setB("B").setC("C").create( );
改写Builder:
//抽象的Builder
public abstract class BuilderWithReturn {
//设置主机
public abstract BuilderWithReturn setBoard(String board);
//设置显示器
public abstract BuilderWithReturn setDisplay(String display);
//设置操作系统
public abstract BuilderWithReturn setOS();
//创建computer
public abstract Computer create();
}
改写MacbookBuilder:
//具体的Builder类
public class MacbookBuilderWithReturn extends BuilderWithReturn{
private Computer macComputer=new Macbook();
@Override
public BuilderWithReturn setBoard(String board) {
macComputer.setmBoard(board);//设置主板
return this;
}
@Override
public BuilderWithReturn setDisplay(String display) {
macComputer.setmDisplay(display);//设置显示器
return this;
}
@Override
public BuilderWithReturn setOS() {
macComputer.setmOs();//设置操作系统
return this;
}
@Override
public Computer create() {
return macComputer;
}
}
客户端实现代码如下:
BuilderWithReturn macbookBuilderWithReturn=new MacbookBuilderWithReturn();
String tag2=macbookBuilderWithReturn.setBoard("IGT主板").setDisplay("AOC显示器").setOS().create().toString();
Log.i("TAG",tag2);
打印结果:
04-16 06:48:45.899 9551-9551/com.troy.builderpattern I/TAG: Computer{mBoard='IGT主板', mDisplay='AOC显示器', mOs='MAC OS X 10.10'}
这种形式不仅没有Director的角色,整个Builder的链式调用也使得结构变得更加简单了。
总结:Builder模式在Android开发中较为常用,通常作为配置类的构建和表示分离开来,同时也是将配置类从目标类中隔离出来,Build模式比较常见的实现形式是通过链式调用,使得代码简洁、易懂。