1. 程式人生 > >Builder模式用於建立複雜物件

Builder模式用於建立複雜物件

這種Builder模式使用靜態內部類實現。當初始化一個物件特別複雜,如引數多,且很多引數都具有預設值時,使用這種模式可以使建立物件的過程更清晰。

比如有一個Request類,代表請求,這個請求有很多屬性。

public final class Request {
    private static final long TOO_LONG_LOG = TimeUnit.SECONDS.toNanos(5);
    private static final int KEY_PADDING = 50; // Determined by exact science.
    static final char KEY_SEPARATOR = '\n';
    int id;
    /** The time that the request was first submitted (in nanos). */
    long started;
    /**
     * uri和resourceId是互斥的
     */
    @Nullable
    public final Uri uri;

    /**
     * resourceId和uir是互斥的
     */
    public final int resourceId;

    @Nullable
    public final Bitmap.Config config;

    /**
     * 快取key
     */
    @Nullable
    public final String key;


    /**
     * 可選的可以替代uri和resourceId的穩定key
     */
    @Nullable
    public final String stableKey;

    /**
     * 使用者追蹤的tag
     */
    @Nullable
    public final Object tag;

    Request(Builder builder){
        this.config = builder.config;
        this.resourceId = builder.resourceId;
        this.uri = builder.uri;
        this.tag = builder.tag;
        this.stableKey = builder.stableKey;
        if (Looper.myLooper() == Looper.getMainLooper()){
            this.key = createKey();
        }else {
            this.key = createKey(new StringBuilder());
        }
    }

    private String createKey(){
        String result = createKey(MAIN_THREAD_KEY_BUILDER);
        MAIN_THREAD_KEY_BUILDER.setLength(0);
        return result;
    }

    private String createKey(StringBuilder sb){
        Request data = this;
        if (data.stableKey != null){
            sb.ensureCapacity(data.stableKey.length() + KEY_PADDING);
            sb.append(data.stableKey);
        }else if (data.uri != null){
            String path = data.uri.toString();
            sb.ensureCapacity(path.length() + KEY_PADDING);
            sb.append(path);
        }else {
            sb.ensureCapacity(KEY_PADDING);
            sb.append(data.resourceId);
        }

        sb.append(KEY_SEPARATOR);
        return sb.toString();
    }

    String logId(){
        long delta = System.nanoTime() - started;
        if (delta > TOO_LONG_LOG){
            return plainId() + "+" + TimeUnit.NANOSECONDS.toSeconds(delta) + "s";
        }
        return plainId() + "+" + TimeUnit.NANOSECONDS.toNanos(delta) + "ms";
    }

    String plainId() {
        return "[R" + id + "]";
    }

    String getName() {
        if (uri != null){
            return String.valueOf(uri.getPath());
        }

        return Integer.toHexString(resourceId);
    }

    /**
     * builder for creating {@link Request}
     */
    public static final class Builder {
        @Nullable Uri uri;
        int resourceId;
        @Nullable String key;
        @Nullable Bitmap.Config config;
        @Nullable Object tag;
        @Nullable String stableKey;


        public Builder (@NonNull Uri uri){
            setUri(uri);
        }

        public Builder(@DrawableRes int resourceId){
            setResourceId(resourceId);
        }

        Builder(@Nullable Uri uri,int resourceId, @Nullable Bitmap.Config bitmapConfig){
            this.uri = uri;
            this.resourceId = resourceId;
            this.config = bitmapConfig;
        }

        Builder(Request request){
            uri = request.uri;
            resourceId = request.resourceId;
            stableKey = request.stableKey;
            config = request.config;
        }

        /**
         * 設定uri,並且重置id
         * @param uri
         * @return
         */
        @NonNull
        public Builder setUri(@NonNull Uri uri) {
            if (uri == null){
                throw new IllegalArgumentException("Image uri may not be null.");
            }
            this.uri = uri;
            this.resourceId = 0;
            return this;
        }

        @NonNull
        public Builder stableKey(@Nullable String stableKey) {
            this.stableKey = stableKey;
            return this;
        }

        /**
         * 設定Id,並且重置uri
         * @param resourceId
         * @return
         */
        @NonNull
        public Builder setResourceId(int resourceId){
            if (resourceId == 0){
                throw new IllegalArgumentException("Image resourceId may not be 0");
            }
            this.resourceId = resourceId;
            this.uri = null;
            return this;
        }

        @NonNull
        public Builder tag(@NonNull Object tag){
            if (tag == null){
                throw new IllegalArgumentException("tag may not be null");
            }
            if (this.tag != null){
                throw new IllegalStateException("tag already set");
            }
            this.tag = tag;
            return this;
        }

        Builder clearTag(){
            this.tag = null;
            return this;
        }

        @Nullable
        Object getTag(){
            return tag;
        }


        @NonNull
        public Builder config(@NonNull Bitmap.Config config){
            checkNotNull(config,"config 是 null");
            this.config = config;
            return this;
        }

        public Request build(){
            return new Request(this);
        }
    }

}

程式碼來自Picasso原始碼,

這樣我們呼叫這個請求就可以:

Request request = new Request.Builder(R.drawable.actionbar_shadow_up).stableKey("1123").build();