Android系统编程思想篇:建造者模式

来源:互联网 发布:手机脚本软件 编辑:程序博客网 时间:2024/04/30 01:07

Android系统编程思想篇:建造者模式

作者: 郭孝星
邮箱: guoxiaoxingse@163.com
博客: http://blog.csdn.net/allenwells
简书: http://www.jianshu.com/users/66a47e04215b/latest_articles

关于作者

郭孝星,非著名程序员,代码洁癖患者,爱编程,好吉他,喜烹饪,爱一切有趣的事物和人。

关于文章

作者的文章会同时发布在Github、CSDN与简书上, 文章顶部也会附上文章的Github链接。如果文章中有什么疑问也欢迎发邮件与我交流, 对于交流
的问题, 请描述清楚问题并附上代码与日志, 一般都会给予回复。如果文章中有什么错误, 也欢迎斧正。如果你觉得本文章对你有所帮助, 也欢迎去
star文章, 关注文章的最新的动态。另外建议大家去Github上浏览文章,一方面文章的写作都是在Github上进行的,所以Github上的更新是最及时
的,另一方面感觉Github对Markdown的支持更好,文章的渲染也更加美观。

文章目录:https://github.com/guoxiaoxing/android-open-source-project-analysis/blob/master/README.md

建造者模式属于创建型模式的一种,它允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造流程。该模式为了将构建复杂对象的
过程和它的部件解耦,使构建的过程和部件的表示隔离开来。

模式定义

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

模式角色

Product:产品的抽象类Builder:抽象Builder类,规范构建过程,一般由子类实现具体构建过程ConcreteBuilder:具体的Builder类Director:统一组装过程

使用场景

1 相同的方法,不同的执行顺序,产生不同的事件结果。2 多个部件或者零件,都可以装配到同一个对象中,但产生的运行结果又不相同。3 对象构建过程特别复杂,参数多,默认值也需要配置。

优点

1 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。2 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。3 可以更加精细地控制产品的创建过程,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。4 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,方便系统扩展,符合“开闭原则”。

缺点

1 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。2 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

另外,以下情况可以做模式简化处理

省略抽象建造者角色:如果系统中只需要一个具体建造者的话,可以省略掉抽象建造者。
省略指挥者角色:在具体建造者只有一个的情况下,如果抽象建造者角色已经被省略掉,那么还可以省略指挥者角色,让Builder角色扮演指挥者与建造者双重角色。

模式实现

我们先来看看完整的建造者模式的实现

抽象产品角色

package com.guoxiaoxing.android.sdk.design.builder.whole;/** * 抽象产品角色,定位一类产品的特性与行为。 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingse@163.com * * @author guoxiaoxing * @since 2017/3/23 上午10:13 */public abstract class AbstractProduct {    private String board;    private String display;    private String os;    public void setBoard(String board) {        this.board = board;    }    public void setDisplay(String display) {        this.display = display;    }    public abstract void setOs(String os);}

具体产品角色

package com.guoxiaoxing.android.sdk.design.builder.whole;/** * 具体产品角色,实现具体的产品特性与行为 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingse@163.com * * @author guoxiaoxing * @since 2017/3/23 上午10:06 */public class RealProduct extends AbstractProduct {    @Override    public void setOs(String os) {        os = "mac osx";    }    /**     * 设置参数内部类,构建的时候先构建参数,完成后再创建实例并装配参数     */    public static class RealProductParams {        public String board;        public String display;        public String os;        public void applyParams(RealProduct product) {            product.setBoard(board);            product.setDisplay(display);            product.setOs(os);        }    }}

抽象建造者角色

package com.guoxiaoxing.android.sdk.design.builder.whole;/** * 抽象建造者橘色,抽象构建行为,具体实现交由子类完成。 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingse@163.com * * @author guoxiaoxing * @since 2017/3/22 下午6:27 */public abstract class AbstractBuilder {    public abstract void setBoard(String board);    public abstract void setDisplay(String display);    public abstract void setOs(String os);}

具体建造者角色

package com.guoxiaoxing.android.sdk.design.builder.whole;/** * 具体建造者橘色,完成具体构建行为。一般持有产品的引用,并在build()方法中返回该引用。 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingse@163.com * * @author guoxiaoxing * @since 2017/3/23 上午10:11 */public class RealBuilder extends AbstractBuilder {    private RealProduct.RealProductParams productParams;    public RealBuilder() {        productParams = new RealProduct.RealProductParams();    }    @Override    public void setBoard(String board) {        productParams.board = board;    }    @Override    public void setDisplay(String display) {        productParams.display = display;    }    @Override    public void setOs(String os) {        productParams.os = os;    }    public RealProduct build() {        RealProduct product = new RealProduct();        productParams.applyParams(product);        return product;    }}

指挥者角色

package com.guoxiaoxing.android.sdk.design.builder.whole;/** * 指挥者角色,指挥多个建造者进行构建过程,当只有一个建造者时此角色可以省略。 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingse@163.com * * @author guoxiaoxing * @since 2017/3/23 上午10:18 */public class Direactor {    private AbstractBuilder builder;    public void setBuilder(AbstractBuilder builder) {        builder = builder;    }    private void buildProduct(String board, String display, String os) {        builder.setBoard(board);        builder.setDisplay(display);        builder.setOs(os);    }}

日常编程中,我们的建造者通常只有一个,这个时候我们可以使用简化版的建造者模式

package com.guoxiaoxing.android.sdk.design.builder.simple;/** * 如果系统中只需要一个具体建造者的话,可以省略掉抽象建造者。在具体建造者只有一个的情况下,如果抽象建造者角色已经被省略 * 掉,那么还可以省略指挥者角色,让Builder角色扮演指挥者与建造者双重角色。 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingse@163.com * * @author guoxiaoxing * @since 2017/3/23 上午10:05 */public class Product {    public String board;    public String display;    public String os;    class Builder {        private Product product;        public Builder() {            product = new Product();        }        private String board;        private String display;        private String os;        public void setBoard(String board) {            product.board = board;        }        public void setDisplay(String display) {            product.display = display;        }        public void setOs(String os) {            product.os = os;        }    }}

模式实践

我们再来看看,我们平时见过的类库都有哪些建造者模式的具体实践。

最为常见的莫过于AlertDialog了吧,在AlertDialog创建的过程中

AlertDialog:内置Builder类,完成参数构建。

AlertController:AlertDialog的代理类,完成具体的构建过程,内置AlertParams类,由Builder类传递过来的参数都会设置到AlertParams中。

AlertDialog内部调用逻辑

AlertController内部调用逻辑

好,我们来看看AlertDialog的具体构建流程。

1 调用Builder,构建参数。

public class Demo{    AlertDialog dialog = new AlertDialog.Builder(context)        .setTitle("标题")        .setMessage("消息")        .create();}

2 调用create()方法,创建AlertDialog实例,同时创建AlertController实例,Builder里的参数传递到了AlertParams里。

public class AlertDialog extends Dialog implements DialogInterface {    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {        super(context, com.android.internal.R.style.Theme_Dialog_Alert);        setCancelable(cancelable);        setOnCancelListener(cancelListener);        mAlert = new AlertController(context, this, getWindow());    }    public AlertDialog create() {        final AlertDialog dialog = new AlertDialog(P.mContext);        P.apply(dialog.mAlert);        dialog.setCancelable(P.mCancelable);        dialog.setOnCancelListener(P.mOnCancelListener);        if (P.mOnKeyListener != null) {            dialog.setOnKeyListener(P.mOnKeyListener);        }        return dialog;    }}

3 调用apply()方法,执行Dialog的创建,设置按钮监听、文字等。

public static class AlertParams {    public void apply(AlertController dialog) {        if (mCustomTitleView != null) {            dialog.setCustomTitle(mCustomTitleView);        } else {            if (mTitle != null) {                dialog.setTitle(mTitle);            }            if (mIcon != null) {                dialog.setIcon(mIcon);            }            if (mIconId >= 0) {                dialog.setIcon(mIconId);            }        }        if (mMessage != null) {            dialog.setMessage(mMessage);        }        if (mPositiveButtonText != null) {            dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,                    mPositiveButtonListener, null);        }        if (mNegativeButtonText != null) {            dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,                    mNegativeButtonListener, null);        }        if (mNeutralButtonText != null) {            dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,                    mNeutralButtonListener, null);        }        if (mForceInverseBackground) {            dialog.setInverseBackgroundForced(true);        }        // For a list, the client can either supply an array of items or an        // adapter or a cursor        if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {            createListView(dialog);        }        if (mView != null) {            if (mViewSpacingSpecified) {                dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,                        mViewSpacingBottom);            } else {                dialog.setView(mView);            }        }        /*        dialog.setCancelable(mCancelable);        dialog.setOnCancelListener(mOnCancelListener);        if (mOnKeyListener != null) {            dialog.setOnKeyListener(mOnKeyListener);        }        */    }}

以上便是AlertDialog德创建过程,可以看出综合使用了代理模式与建造者模式,当create()方法被调用时才创建出了对象,当apply()方法被
调用的时候,才对对象进行属性设置。

事实上,Builder在创建时它只创建了AlertParams的实例,并没有去创建AlertDialog,这种写法也是懒加载的一种体现,有利于节省资源。

public static class Builder {    private final AlertController.AlertParams P;    public Builder(@NonNull Context context, @StyleRes int themeResId) {        P = new AlertController.AlertParams(new ContextThemeWrapper(                context, resolveDialogTheme(context, themeResId)));        mTheme = themeResId;    }}

以上便是Android系统中对建造者模式的应用,可以发现该实践中并没有抽象产品角色、指挥者角色,这是Android对建造者模式的一种简化,在后续的阅读源码过程中还会发现
很多这样的简化与变通,并不是刻板的按照标准实现来做,这也正是编程的魅力所在:因地制宜,灵活多变。

关于Dialog的进一步的内容以及WindowManager等相关原理,我们在这里不再进一步展开,后续的Android源码分析系列文章中会做进一步的详尽分析。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机不兼容高版本微信怎么办 绝地求生右下角小地图变大了怎么办 杯孕当月做了C丁怎么办 玩全军出击手机发烫就出现卡怎么办 不小心买了彩虹六号肝帝版本怎么办 微信游戏刺激战场电脑卡怎么办 电脑更新了以前的东西都没了怎么办 安装黑苹果鼠标键盘不能用怎么办 苹果开机卡在白底黑苹果怎么办 信长之野望14没有剧情触发怎么办 玩cf手游手机屏幕摩擦力大怎么办 网吧有战地1没有橘子平台怎么办 俩人打仗了对方想讹我怎么办 环世界模组装多了打不开怎么办 手机百度云视频播放画面太小怎么办 ps文件说数据似乎已经损坏怎么办 百度云中的压缩包下载的很慢怎么办 游戏压缩出现未知错误或损坏怎么办 百度云里的压缩包解压后损坏怎么办 联创打印时显示压缩文件失败怎么办 电脑的软件打开出现未知格式怎么办 图片只突出人物边上全黑怎么办 合金机兵存档密码忘了怎么办 手机网页验证码无法加载插件怎么办 绝地求生次激战场机型不支持怎么办 木茷生存中文版安装包损坏了怎么办 手机下载软件显示安装包损坏怎么办 不小心把qq图片删了怎么办 奶水不足宝宝不好好吸奶怎么办 膀胱切除前列腺切除阴茎不硬怎么办 小孩的睾丸睾丸碰肿了怎么办 怎么判断小孩子的睾丸没下来怎么办 怀孕39周腰酸屁股酸疼该怎么办 我儿子18岁睾丸筋鼓起来怎么办 去医院检查说精子跑的慢怎么办 多囊卵巢综合症引起屁股增大怎么办 蚊子咬了肿了挠破了流水怎么办 血糖高引发的睾丸一直烂怎么办? 被洪水淹过的猪后期怎么办 做睾丸阴囊彩超阴茎突然勃起怎么办 阴茎冠状沟皮肤感染总不愈合怎么办