(《设计模式解析与实战》读书笔记)
一、定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
二、使用场景:
1 相同的方法,不同的执行顺序,产生不同的事件结果时;
2 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时;
3 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用;
4 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。
三、简单示例(计算机组装):
/**
* 计算机抽象类
*
*/
public abstract class Computer {
// CPU核心
protected String mBoard;
// 显示内存
protected String mDisplay;
// 操作系统
protected String mOS;
protected Computer() {
}
public void setBoard(String board) {
this.mBoard = board;
}
public void setDisplay(String display) {
this.mDisplay = display;
}
public abstract void setOS();
@Override
public String toString() {
return "Computer [mBoard=" + mBoard + ", mDisplay=" + mDisplay + ", mOS=" + mOS + "]";
}
}
/**
* 具体的Computer类,Macbook
*
*/
public class Macbook extends Computer {
protected Macbook() {
}
@Override
public void setOS() {
mOS = "Mac OS X 10.10";
}
}
/**
* 抽象的Build类
*
*/
public abstract class Builder {
// 设置主机
public abstract void buildBoard(String board);
// 设置显示器
public abstract void buildDisplay(String display);
// 设置操作系统
public abstract void buildOS();
// 创建Computer
public abstract Computer create();
}
/**
* 具体的Builder类,MacbookBuilder
*
*/
public class MacbookBuilder extends Builder{
private Computer mComputer = new Macbook();
@Override
public void buildBoard(String board) {
mComputer.setBoard(board);
}
@Override
public void buildDisplay(String display) {
mComputer.setDisplay(display);
}
@Override
public void buildOS() {
mComputer.setOS();
}
@Override
public Computer create() {
return mComputer;
}
}
Director和Builder一起将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象。
/**
* 构造Computer
*
*/
public class Director {
Builder mBuilder = null;
public Director(Builder mBuilder) {
this.mBuilder = mBuilder;
}
/**
* 构建对象
*
* @param board
* @param display
*/
public void construct(String board, String display) {
mBuilder.buildBoard(board);
mBuilder.buildDisplay(display);
mBuilder.buildOS();
}
}
/**
* 测试Builder
*
*/
public class BuildTest {
public static void main(String[] args) {
// 构建器
Builder builder = new MacbookBuilder();
Director director = new Director(builder);
// 封装构建过程
director.construct("英特尔主板", "Retina显示器");
// 构建计算机,输出相关信息
System.out.println("计算机信息:" + builder.create().toString());
}
}
四、优缺点:
Builder模式常见的实现形式是通过调用链实现,这样使得代码更简介、易懂,比如AlertDialog.Builder。
优点:
(1)良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节;
(2)建造者独立,容易扩展。
缺点:
会产生多余的Builder对象以及Director对象,消耗内存。
UML类图:
五、实例:
比如ImageLoader,它只能在构建时设置各个参数,一旦调用build()或者类似方法构建对象之后,它的属性就不可更改,用户只能在初始化时一次性构造这个配置对象,然后注入给ImageLoader,ImageLoader根据配置对象进行初始化。代码如下:
public final class ImageLoader {
// 图片加载配置对象
private ImageLoaderConfig mConfig;
// 省略单例模式的代码
/**
* 初始化ImageLoader
* @param config
*/
public void init(ImageLoaderConfig config) {
mConfig = config;
// 检测配置的合法性,内部会根据配置做一些初始化操作
checkConfig();
// 代码省略
}
// 加载图片的函数
public void displayImage(String imageUrl, ImageView imageView) {
Bitmap bitmap = mImageCache.get(imageUrl);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
return;
}
// 添加加载请求
submitLoaderRequest(imageUrl, imageView);
}
private void submitLoaderRequest(String imageUrl, final ImageView imageView) {
// 代码省略
}
public Bitmap downloadImage(String imageUrl) {
Bitmap bitmap = null;
// 代码省略
return bitmap;
}
}
public class ImageLoaderConfig {
// 图片缓存配置对象
BitmapCache bitmapCache = new MemoryCache();
// 加载图片时的loading和加载失败的图片配置对象
DisplayConfig displayConfig = new DisplayConfig();
// 加载策略
LoadPolicy loadPolicy = new SerialPolicy();
// 线程数量,默认为CPU数量 + 1
int threadCount = Runtime.getRuntime().availableProcessors() + 1;
private ImageLoaderConfig() {
}
/**
* 配置类的Builder
*/
public static class Builder {
BitmapCache bitmapCache = new MemoryCache();
DisplayConfig displayConfig = new DisplayConfig();
LoadPolicy loadPolicy = new SerialPolicy();
int threadCount = Runtime.getRuntime().availableProcessors() + 1;
// 设置线程数量
public Builder setThreadCount(int count) {
threadCount = Math.max(1, count);
return this;
}
// 设置缓存
public Builder setCache(BitmapCache cache) {
bitmapCache = cache;
return this;
}
// 设置图片加载中显示的图片
public Builder setLoadingPlaceholder(int resId) {
displayConfig.loadingResId = resId;
return this;
}
// 设置要加载时显示失败的图片
public Builder setNotFoundPlaceholder(int resId) {
displayConfig.failedResId = resId;
return this;
}
// 设置加载策略
public Builder setLoadPolicy(LoadPolicy policy) {
if (policy != null) {
loadPolicy = policy;
}
return this;
}
void applyConfig(ImageLoaderConfig config) {
config.bitmapCache = this.bitmapCache;
config.displayConfig = this.displayConfig;
config.loadPolicy = this.loadPolicy;
config.threadCount = this.threadCount;
}
public ImageLoaderConfig create() {
ImageLoaderConfig config = new ImageLoaderConfig();
// 应用配置
applyConfig(config);
return config;
}
}
}
代码调用:
private void initImageLoader() {
ImageLoaderConfig config = new ImageLoaderConfig.Builder()
.setLoadingPlaceholder(R.drawable.ic_launcher)
.setNotFoundPlaceholder(R.drawable.ic_launcher)
.setCache(new DoubleCache(this)).setThreadCount(4)
.setLoadPolicy(new ReversePolicy())
.create();
// 将配置初始化到ImageLoader中
ImageLoader.getInstance().init(config);
}
当然上面有很多类未写出来,重要的是Builder模式思想。