Android设计模式-Builder模式
Posted vanpersie_9987
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android设计模式-Builder模式相关的知识,希望对你有一定的参考价值。
Builder模式介绍
Builder模式是一步一步创建一个复杂对象的创建型模式,它允许用户再不知道内部构建细节的情况下,更精细地控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。
因为一个复杂的对象有很多大量组成的部分,如汽车,有车轮、方向盘、发动机,还有各种小零件等。如何将这些部件装配成一辆汽车,这个过程很复杂,对于这种情况,为了在构建过程中对外部隐藏实现细节,两者之间的耦合也降到最低。
Builder模式的定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过长可以创建不同的表示。
Builder模式的使用场景
(1)相同的方法,不同的执行顺序,产生不同的事件结果时。
(2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
(3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适。
(4)当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。
Builder模式的简单实现
以计算机的组装过程为例,它的组装过程较为复杂,且组装顺序是不固定的,为了易于理解,我们把计算机组装的过程贱货为构建主机、设置操作系统、设置显示器三个部分,然后通过Director和具体的Builder来构建计算机对象:
//计算机抽象类,即Productor角色
public abstract class Computer
protected String mBoard;
protected String mDisplay;
protected String mOS;
protected Computer()
//设置主板
public void setBoard(String board)
mBoard = board;
//设置显示器
public void setDisplay(String display)
mDisplay = display;
//设置操作系统
public abstract void setOS();
@Override
public String toString()
return "Computor [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";
//抽象Builder类
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类, 负责构造Computer
public class Director
Builder mBuilder = null;
public Director(Builder builder)
mBuilder = builder;
public void construct(String board, String display)
mBuilder.buildBoard(board);
mBuilder.buildDisplay(display);
mBuilder.buildOS();
//测试代码
public class Test
public static void main(String[] args)
Builder builder = new MacbookBuilder();
Director pcDirector = new Director(builder);
pcDirector.construct("英特尔主板", "Retina显示器");
//构建计算机,输出相关信息
System.out.println("Computer Info : " + builder.create().toString());
//输出
Computer Info : Computer [mBoard=英特尔主板, mDisplay=Retina 显示器, MOS=Mac OS X 10.10]
上述示例中,通过具体的MacBookBuilder来构建Macbook对象,而Director封装了构建复杂产品对象的过程,对外隐藏构建细节。Builder与Director一起讲一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象。
在现实的开发中,Director角色常被省略。而直接使用一个Builder来进行对象的组装,这个Builder通常为链式调用,它的调用关键点是每个setter方法都返回吱声,也就是return this :
new TestBuilder().settA("A").setB("B").create();
这种形式不仅去除了Director角色,整个结构也更简单,也能对Product对象的组装过程有更精细的控制。
Builder模式实战
下面以配置ImageLoader为例,使用Builder模式为其设置图片在加载时ImageView显示的图片、加载失败后显示的图片、图片加载引擎线程数等。
public class ImageLoader
//图片缓存
ImageCache mImageCache = new MemoryCache();
//图片加载中显示的图片id
int mLoadingImageId;
//加载失败时显示的图片id
int mLoadingFailedImageId;
//图片加载策略
LoaderPolicy mLoaderPolicy;
//线程池,线程数量为CPU的数量
ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().avaliableProccessors());
//省略单例模式的部分代码
public void displayImage(String imageUrl, ImageView imageView)
Bitmap bitmap = mImageCache.get(imageUrl);
if(bitmap != null)
imageView.setImageBitmap(bitmap);
return;
//提交图片加载请求
submitLoadRequest(imageUrl, imageView);
public void setImageCache(ImageCache cache)
mImageCache = cache;
public void setLoadingCache(int resId)
mLoadingImageid = resId;
public void setLoadingFailedImage(int resId)
mLoadingFailedImageId = resId;
public void setLoadingPolicy(LoaderPolicy policy)
mLoadingPolicy = policy;
public void setThreadCount(int count)
mExecutorService.shutdown();
mExecutorService = null;
//设置新的线程数量
mExecutorService = Executors.newFixedThreadPool(count);
private void submitLoadRequest(final String imageUrl, final ImageView imageView)
//设置加载中的图片
imageView.setImageResource(mLoadingImageUrl);
imageView.setTag(imageUrl);
mExecutorService.submit(new Runnable()
@Override
public void run()
//加载图片
Bitmap bitmap = downloadImage(imageUrl);
if(bitmap == null)
//设置加载图片失败后显示的图片
imageUrl.setImageResource(mLoadingFailedImageId);
return;
//显示加载到的图片
);
public Bitmap downloadImage(String imageUrl)
Bitmap bitmap = null;
// ...省略下载过程
return bitmap;
这段代码就是创建对应的成员变量,然后通过setter方法来设置这些变量值,使得这些特性都能被用户定制。
但是存在的问题是,ImageLoader中方法较多,且用户可以在任何时候修改ImageLoader的配置。比如已经初始化了一个指定线程数量的线程池的情况下,用户再调用setThreadCount时就会出现问题。里面过多的函数暴露,也让用户在每次调用函数时都要仔细选择。
而使用Builder就能解决上述问题,即“将一个复杂对象的构建与它的表示分离”,然后用Builder模式来构建一个不可变的配置对象,并且将这个配置对象注入到ImageLoader中,也就是说它只能在构建时设置各个参数,一旦调用了build()方法,它的属性就不可再修改,因为它没有setter方法,字段也是隐藏的,用户只能在初始化时一次性构造这个配置对象,然后注入给ImageLoader。
这是修改后的ImageLoader:
public final class ImageLoader
//图片加载配置对象
private ImageLoaderConfig mConfig;
//... 省略单例模式代码
... ...
//初始化ImageLoader
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;
//添加加载请求
submitLoadRequest(imageUrl, imageUrl);
private void submitLoadRequest(final String imageUrl, final ImageView imageView)
//...省略
public Bitmap downloadImage(String imageUrl)
Bitmap bitmap = null;
//...省略
... ...
return bitmap;
上面的代码,把配置的代码基本都封到了ImageLoaderConfig和Builder对象中。
public class ImageLoaderConfig
//图片缓存配置对象
BitmapCache bitmapCache = new MemeoryCache();
//加载图片时的loading和加载失败的图片配置对象
DisplayConfig displayConfig = new DisplayConfig();
//加载策略
LoadPolicy loadPolicy = new SerialPolicy();
//线程数量,默认为CPU数量 + 1
int threadCount = Runtime.getRuntime().availableProccessors() + 1;
private ImageLoaderConfig()
//配置类的Builder
public static class Builder
//图片缓存配置对象
BitmapCache bitmapCache = new MemeoryCache();
//加载图片时的loading和加载失败的图片配置对象
DisplayConfig displayConfig = new DisplayConfig();
//加载策略
LoadPolicy loadPolicy = new SerialPolicy();
//线程数
int threadCount = Runtime.getRuntime().availableProccessors() + 1;
public Builder setThreadCount(int count)
threadCount = Math.max(1, count);
return this;
//设置缓存
public Builder setCache(Bitmapcache cache)
bitmapCache = cache;
//设置图片加载中显示的图片
public Builder setLoadingPlaceholder(int resId)
displayConfig.laodingResId = resId;
return this;
//设置要加载的图片加载失败时显示的图片
public Builder setNotPlaceholder(int resId)
displayConfig.failedResIs = resId;
return this;
//设置加载策略
public Builder setLoadiPolicy(LoadPolicy policy)
if(policy != null)
loadPolicy = policy;
return this;
public 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;
通过将ImageLoaderConfig的构造函数、字段私有化,使得外部不能访问内部属性,用户唯一能够设置属性的地方就是通过Builder对象。
用户将这样使用Builder模式:
private void initImageLoader()
ImageLoaderConfig config = new ImageLoaderConfig.Builder().setLoadingPlaceholder(R.drawable.loading).setNotFoundPlaceholder(R.drawable.not_found).setCache(new DoubleCache(this)).setThreadCount(4).setLoadPolicy(new ReversePolicy()).create();
//将配置初始化到ImageLoader中
ImageLoader.getInstance().init(config);
调用init函数之后,ImageLoader就可以正常使用了,各种setter函数不会在用户调用ImageLoader方法时出现在视野中,它们已经被隔离到了Builder模式中。
总结
Builder模式在android开发中较为常用,通常作为配置类的构建器将配置的构建和表示分离开来,同时也是将配置从目标类中隔离出来,避免过多的setter方法。Builder模式比较常见的实现形式是通过调用链实现,这样的代码更简洁、易懂。
- 优点:
(1)良好的封装性,使用构建者模式可以使客户端不必知道内部的组成细节。
(2)建造者独立,容易扩展。
缺点:
会产生多于的Builder对象以及Director对象,消耗内存。
以上是关于Android设计模式-Builder模式的主要内容,如果未能解决你的问题,请参考以下文章