2018-01-12

java设计模式(二) 建造者模式

miss2008

关注

2017-10-02 10:24 · 字数 531 · 阅读 172 ·  Java设计模式

建造者模式一句话概括:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建出不同的表示。

--. 定义要点分析

1,模式功能:最终目的是为了建造一个对象Product,在对象构建时才会使用建造者模式。

2,复杂对象:我们要创建的对象是复杂的,所以内部细节会很繁琐,需要把对象各个组成部分封装处理。

            当对象构建过程简单时,别滥用这个设计模式。

3,构建和表示分离:对象的构建细节和最终表示解耦,即需要一个建造者Builder,只负责对象的每个组成的

            内部实现,还需要有一个导演者Director,通过Builder把对象按步骤拼装起来。

4,“相同”的构建过程,不同的表示:一个复杂对象,建造过程相同,但是建造的每一步的内部细节实现不同,

            产生出不同的对象表示。实际场景里,相同的构建方法,不同的组装顺序,产生不同的结果也会

            使用建造者模式,这个相同更多的体现在产品的组成相同,即Builder里的方法相同

举例:安卓App的开发过程,App就是需要生产的产品,有不同的App如QQ和微信,各种App内部细节是不同的

    ,但是app需要在安卓系统中存在并运行,其组成是相同(界面,数据,缓存...)。

--. 建造者模式基本类图如下:

建造者模式类图.png

--. 建造者的基本使用(以上面app开发为例)

抽象建造者,规范app的组成

public interface IAppBuilder {

    public void addView();

    public void addData();

    public void addCache();

    public App buildProduct();

}

抽象app产品,因为要制造不同的app

public abstract class App {

    public String view;

    public String data;

    public String cache;

    public String getView() {return view;}

    public void setView(String view) { this.view = view;}

    public String getData() {return data;}

    public void setData(String data) {this.data = data;}

    public String getCache() {return cache;}

    public void setCache(String cache) {this.cache = cache;}

}

public class Qq extends App {}

public class Weixin extends App {}

具体构建者(只展示QQ构建者,微信类似)

public class QqBuilder implements IAppBuilder {

    private final App app;

    public QqBuilder() {app = new Qq();}

    @Override

    public void addView() {app.setView("QQ界面");}

    @Override

    public void addData() {app.setData("QQ数据");}

    @Override

    public void addCache() {app.setCache("QQ缓存");}

    @Override

    public App buildProduct() {return app;}

}

导演

public class Director {

    public IAppBuilder appBuilder;

    public Qq buildQq() {

        appBuilder = new QqBuilder();

        appBuilder.addView();

        appBuilder.addData();

        appBuilder.addCache();

        return (Qq) appBuilder.buildProduct();

    }

    public Weixin buildWeixin() {

        appBuilder = new WeixinBuilder();

        appBuilder.addView();

        appBuilder.addData();

        appBuilder.addCache();

        return (Weixin) appBuilder.buildProduct();

    }

}

--. 复杂的建造者模式

在实际开发中,Director往往被忽视,大家习惯直接用Builder来进行对象的组装,这个Builder通常为链式调用,即每个组装方法里都返回自身(return this),这样既简化了结构,也使组装过程更清晰。

Product product = new Builder().setA().setB().build();

类图大致如下

复杂的建造者模式.png

去除Director,上面样例Builder改为如下

public class QqBuilder implements IAppBuilder {

    private final App app;

    public QqBuilder() { app = new Qq();}

    @Override

    public IAppBuilder addView() {

        app.setView("QQ界面");

        return this;

    }

    @Override

    public IAppBuilder addData() {

        app.setData("QQ数据");

        return this;

    }

    @Override

    public IAppBuilder addCache() {

        app.setCache("QQ缓存");

        return this;

    }

    @Override

    public App buildProduct() {

        return app;

    }

}

--. 框架里的建造者模式(Retrofit为例)

在常用框架里,会对建造者模式的结构进一步简化,把构建者直接放到生产的产品Product里,作为一个抽象内部类。

Prodect product = new Product.Builder().setA().setB().build();

框架建造者.png

Retrofit是网络调度层框架,调用网络执行层框架Okhttp完成网络请求,封装线程切换,数据转换等功能,下面简化代码可以看到,在Builder里传入路径、Httpclient、响应方式、数据转换器等完成Retrofit的构建。

public final class Retrofit {

    final okhttp3.Call.Factory callFactory;

    final HttpUrl baseUrl;

    final List<Converter.Factory> converterFactories;

    final List<CallAdapter.Factory> adapterFactories;

    final @Nullable

    Executor callbackExecutor;

    final boolean validateEagerly;

    Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,

            List<Converter.Factory> converterFactories, List<CallAdapter.Factory>

            adapterFactories,

            @Nullable Executor callbackExecutor, boolean validateEagerly) {

        this.callFactory = callFactory;

        this.baseUrl = baseUrl;

        // Defensive copy at call site.

        this.converterFactories = unmodifiableList(converterFactories);

        // Defensive copy at call site.

        this.adapterFactories = unmodifiableList(adapterFactories);       

        this.callbackExecutor = callbackExecutor;

        this.validateEagerly = validateEagerly;

    }

    public okhttp3.Call.Factory callFactory() {

        return callFactory;

    }

    public HttpUrl baseUrl() {

        return baseUrl;

    }

    ...

    /**

    * Build a new {@link Retrofit}.

    * <p>

    * Calling {@link #baseUrl} is required before calling {@link #build()}. All

    * other methods are optional.

    */

    public static final class Builder {

        private final Platform platform;

        private @Nullable okhttp3.Call.Factory callFactory;

        private HttpUrl baseUrl;

        private final List<Converter.Factory> converterFactories

                                  = new ArrayList<>();

        private final List<CallAdapter.Factory> adapterFactories

                                  = new ArrayList<>();

        private @Nullable Executor callbackExecutor;

        private boolean validateEagerly;

        public Builder() {

            this(Platform.get());

        }

        public Builder client(OkHttpClient client) {

            return callFactory(checkNotNull(client, "client == null"));

        }

        public Builder callFactory(okhttp3.Call.Factory factory) {

            this.callFactory = checkNotNull(factory, "factory == null");

            return this;

        }

        public Builder baseUrl(String baseUrl) {

            HttpUrl httpUrl = HttpUrl.parse(baseUrl);

            return baseUrl(httpUrl);

        }

        public Builder addConverterFactory(Converter.Factory factory) {

            converterFactories.add(checkNotNull(factory, "factory == null"));

            return this;

        }

        public Builder addCallAdapterFactory(CallAdapter.Factory factory) {

            adapterFactories.add(checkNotNull(factory, "factory == null"));

            return this;

        }

        public Builder callbackExecutor(Executor executor) {

            this.callbackExecutor = checkNotNull(executor, "executor == null");

            return this;

        }

        public Builder validateEagerly(boolean validateEagerly) {

            this.validateEagerly = validateEagerly;

            return this;

        }

        public Retrofit build() {

            return new Retrofit(callFactory, baseUrl, converterFactories

                    , adapterFactories,callbackExecutor, validateEagerly);

        }

    }

}

总结:

建造者模式是一种对象构建的模式,它侧重对象组件的封装和装配顺序,在我们开发过程中,链式结构的用法在外形上更能体现这个模式,不过当产品组成部分过多时,还是使用Director更符合单一职责功能,Director也能起一层封装作用,避免高层代码接触内部细节。

其他模式链接如下:

java设计模式(一) 观察者模式

java设计模式(三) 代理模式

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 前言 使用Retrofit已经一段时间了,这货挺好用的,还很特别,特别是使用接口来定义请求方式,这用法让我对它的源...
    带心情去旅行阅读 3,358评论 3 21
  • 简介 刚接触Retrofit的时候,就写了一篇简单的使用介绍:Retrofit 2.0基本使用方法,算是对Retr...
    Whyn阅读 2,841评论 4 24
  • //1.4.2指针与复制构造函数 include<bits/stdc++.h> using namespace s...
    三笠_149f阅读 162评论 0 0
  • 一、调用代码使APP进入后台,达到点击Home键的效果。 [[UIApplication sharedApplic...
    郑军红阅读 222评论 0 0