Android 最常用的设计模式十一 安卓源码分析——建造者模式

2017-09-13 20:37:01来源:CSDN作者:WHB20081815人点击

分享


我的理解:就是构造函数的时候,可以灵活的设置它的值,如果构造函数很多的值,不用全部传,需要什么值,就放什么值,封装了set方法一样,一步一步构造自己想要的属性


 它的意思就是将一个对象和怎么构建这个对象分离开来,如果你想构建一个对象,你把这个消息告诉构建者,并且将自己对这个对象的各种要求告诉建造者,然后建造者根据这 些要求进行捣鼓,然后,你所需要的一个对象就出来了。


BUILDER—MM最爱听的就是“我爱你”这句话了,见到不同地方的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM我只要按对应的键,它就能够用相应的语言说出“我爱你”这句话了,国外的MM也可以轻松搞定,这就是我的“我爱你 ”builder。(这一定比美军在伊拉克用的翻译机好卖) 

建造模式:将对象的内部表象和对象的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。 


      建造者模式把构造和表示分离开,根据客户需求生产一个相应的对象。
本来呢,我们根据Builder接口实现不同的具体的ConcreteBuilder,就可生产不同的对象了。
但是,下面例子的只有一个Builder,所以也没有接口Builder,也没有其他的ConcreteBuilder。
但是我今天要讲的例子太简单,简单到都不觉得是建造者模式,但是又有建造者模式的感觉。

建造者模式:AlertDialog.Builder

简介:可以分步地构造每一部分。


AlertDialog里面有一个静态类builder,里面封装什么设置按钮的文字的


public static class Builder {    private final AlertController.AlertParams P;    /**     * Creates a builder for an alert dialog that uses the default alert     * dialog theme.     * <p>     * The default alert dialog theme is defined by     * {@link android.R.attr#alertDialogTheme} within the parent     * {@code context}'s theme.     *     * @param context the parent context     */    public Builder(Context context) {        this(context, resolveDialogTheme(context, 0));    }


public class AlertDialog extends Dialog implements DialogInterface {    private AlertController mAlert;    /**     * Hint layout to the side.     * @hide     */    public static final int LAYOUT_HINT_SIDE = 1;    /**     * Creates an alert dialog that uses the default alert dialog theme.     * <p>     * The default alert dialog theme is defined by     * {@link android.R.attr#alertDialogTheme} within the parent     * {@code context}'s theme.     *     * @param context the parent context     * @see android.R.styleable#Theme_alertDialogTheme     */    protected AlertDialog(Context context) {        this(context, 0);    }    /**     * Creates an alert dialog that uses the default alert dialog theme and a     * custom cancel listener.     * <p>     * This is functionally identical to:     * <pre>     *     AlertDialog dialog = new AlertDialog(context);     *     alertDialog.setCancelable(cancelable);     *     alertDialog.setOnCancelListener(cancelListener);     * </pre>     * <p>     * The default alert dialog theme is defined by     * {@link android.R.attr#alertDialogTheme} within the parent     * {@code context}'s theme.     *     * @param context the parent context     * @see android.R.styleable#Theme_alertDialogTheme     */    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {        this(context, 0);        setCancelable(cancelable);        setOnCancelListener(cancelListener);    }    /**     * Gets the list view used in the dialog.     *     * @return The {@link ListView} from the dialog.     */    public ListView getListView() {        return mAlert.getListView();    }    @Override    public void setTitle(CharSequence title) {        super.setTitle(title);        mAlert.setTitle(title);    }       /**     * Set resId to 0 if you don't want an icon.     * @param resId the resourceId of the drawable to use as the icon or 0     * if you don't want an icon.     */    public void setIcon(@DrawableRes int resId) {        mAlert.setIcon(resId);    }    public void setIcon(Drawable icon) {        mAlert.setIcon(icon);    }    public static class Builder {        private final AlertController.AlertParams P;        /**         * Creates a builder for an alert dialog that uses the default alert         * dialog theme.         * <p>         * The default alert dialog theme is defined by         * {@link android.R.attr#alertDialogTheme} within the parent         * {@code context}'s theme.         *         * @param context the parent context         */        public Builder(Context context) {            this(context, resolveDialogTheme(context, 0));        }        /**         * Creates a builder for an alert dialog that uses an explicit theme         * resource.         * <p>         * The specified theme resource ({@code themeResId}) is applied on top         * of the parent {@code context}'s theme. It may be specified as a         * style resource containing a fully-populated theme, such as         * {@link android.R.style#Theme_Material_Dialog}, to replace all         * attributes in the parent {@code context}'s theme including primary         * and accent colors.         * <p>         * To preserve attributes such as primary and accent colors, the         * {@code themeResId} may instead be specified as an overlay theme such         * as {@link android.R.style#ThemeOverlay_Material_Dialog}. This will         * override only the window attributes necessary to style the alert         * window as a dialog.         * <p>         * Alternatively, the {@code themeResId} may be specified as {@code 0}         * to use the parent {@code context}'s resolved value for         * {@link android.R.attr#alertDialogTheme}.         *         * @param context the parent context         * @param themeResId the resource ID of the theme against which to inflate         *                   this dialog, or {@code 0} to use the parent         *                   {@code context}'s default alert dialog theme         */        public Builder(Context context, int themeResId) {            P = new AlertController.AlertParams(new ContextThemeWrapper(                    context, resolveDialogTheme(context, themeResId)));        }        /**         * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.         * Applications should use this Context for obtaining LayoutInflaters for inflating views         * that will be used in the resulting dialogs, as it will cause views to be inflated with         * the correct theme.         *         * @return A Context for built Dialogs.         */        public Context getContext() {            return P.mContext;        }        /**         * Set the title using the given resource id.         *         * @return This Builder object to allow for chaining of calls to set methods         */        public Builder setTitle(@StringRes int titleId) {            P.mTitle = P.mContext.getText(titleId);            return this;        }


简单说就是把自个儿构造函数变成了保护类型,就不能主动创建了。那么创建需要一个使用它内部类Builder


ImageLoader的源码也用了构造者模式


public final class ImageLoaderUtil {    // ImageLoader初始化    static {        File cacheDir = StorageUtils.getOwnCacheDirectory(CXApplication.mAppContext, "imgCache");        FileNameGenerator fileNameGenerator = new Md5FileNameGenerator();//        UnlimitedDiskCache diskCache = new UnlimitedDiskCache(cacheDir, null, fileNameGenerator);        UsingFreqLimitedMemoryCache memoryCache = new UsingFreqLimitedMemoryCache((int) (Runtime.getRuntime().maxMemory() / 16));// 缓存内存大小        DisplayImageOptions displayImageOptions = new DisplayImageOptions                .Builder()                .cacheOnDisk(true)/* 磁盘缓存 */                .cacheInMemory(true) /* 内存缓存 */                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2).bitmapConfig(Bitmap.Config.RGB_565)                .showImageOnLoading(R.drawable.j_iv_loading)// 加载过程图片                .showImageOnFail(R.drawable.j_iv_loading_fail_large)// 失败图片                .build();        ImageLoaderConfiguration imageLoaderConfiguration = new ImageLoaderConfiguration                .Builder(CXApplication.mAppContext)                .diskCache(diskCache)                .memoryCache(memoryCache)                .defaultDisplayImageOptions(displayImageOptions)                .denyCacheImageMultipleSizesInMemory()                .threadPoolSize(4)// 线程池内加载的数量                .tasksProcessingOrder(QueueProcessingType.FIFO)// 先进先出                .memoryCacheExtraOptions(CXLocConfig.ScreenWidthPixels, CXLocConfig.ScreenHeightPixels)// 最大内存缓存图片宽高                .diskCacheFileCount(100)// 磁盘最多缓存100张图片                .diskCacheSize(50 * 1024 * 1024)// 磁盘最大缓存50M的图片                .memoryCache(new WeakMemoryCache())                .memoryCacheSizePercentage(15)                .build();        ImageLoader.getInstance().init(imageLoaderConfiguration);// 全局初始化此配置    }

public final class DisplayImageOptions {    private final int imageResOnLoading;    private final int imageResForEmptyUri;    private final int imageResOnFail;    private final Drawable imageOnLoading;    private final Drawable imageForEmptyUri;    private final Drawable imageOnFail;    private final boolean resetViewBeforeLoading;    private final boolean cacheInMemory;    private final boolean cacheOnDisk;    private final ImageScaleType imageScaleType;    private final Options decodingOptions;    private final int delayBeforeLoading;    private final boolean considerExifParams;    private final Object extraForDownloader;    private final BitmapProcessor preProcessor;    private final BitmapProcessor postProcessor;    private final BitmapDisplayer displayer;    private final Handler handler;    private final boolean isSyncLoading;    private DisplayImageOptions(DisplayImageOptions.Builder builder) {        this.imageResOnLoading = builder.imageResOnLoading;        this.imageResForEmptyUri = builder.imageResForEmptyUri;        this.imageResOnFail = builder.imageResOnFail;        this.imageOnLoading = builder.imageOnLoading;        this.imageForEmptyUri = builder.imageForEmptyUri;        this.imageOnFail = builder.imageOnFail;        this.resetViewBeforeLoading = builder.resetViewBeforeLoading;        this.cacheInMemory = builder.cacheInMemory;        this.cacheOnDisk = builder.cacheOnDisk;        this.imageScaleType = builder.imageScaleType;        this.decodingOptions = builder.decodingOptions;        this.delayBeforeLoading = builder.delayBeforeLoading;        this.considerExifParams = builder.considerExifParams;        this.extraForDownloader = builder.extraForDownloader;        this.preProcessor = builder.preProcessor;        this.postProcessor = builder.postProcessor;        this.displayer = builder.displayer;        this.handler = builder.handler;        this.isSyncLoading = builder.isSyncLoading;    }    public boolean shouldShowImageOnLoading() {        return this.imageOnLoading != null || this.imageResOnLoading != 0;    }    public boolean shouldShowImageForEmptyUri() {        return this.imageForEmptyUri != null || this.imageResForEmptyUri != 0;    }    public boolean shouldShowImageOnFail() {        return this.imageOnFail != null || this.imageResOnFail != 0;    }        boolean isSyncLoading() {        return this.isSyncLoading;    }    public static DisplayImageOptions createSimple() {        return (new DisplayImageOptions.Builder()).build();    }    public static class Builder {



如Gson中的GsonBuilder,代码太长了,就不贴了,有兴趣自己去看源码,这里只贴出其Builder的使用方法。


GsonBuilder builder=new GsonBuilder();
Gson gson=builder.setPrettyPrinting()
.disableHtmlEscaping()
.generateNonExecutableJson()
.serializeNulls()
.create();

EventBus中也有一个Builder,只不过这个Builder外部访问不到而已,因为它的构造函数不是public的,但是你可以在EventBus这个类中看到他的应用

public static EventBusBuilder builder() {
return new EventBusBuilder();
}
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();
typesBySubscriber = new HashMap<Object, List<Class<?>>>();
stickyEvents = new ConcurrentHashMap<Class<?>, Object>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}

网络请求框架OkHttp
private Response(Builder builder) {
this.request = builder.request;
this.protocol = builder.protocol;
this.code = builder.code;
this.message = builder.message;
this.handshake = builder.handshake;
this.headers = builder.headers.build();
this.body = builder.body;
this.networkResponse = builder.networkResponse;
this.cacheResponse = builder.cacheResponse;
this.priorResponse = builder.priorResponse;
}


参考博客:

https://my.oschina.net/weiCloudS/blog/392872


http://blog.csdn.net/fofu33/article/details/50973172



最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台