美文网首页
Android系统编程思想篇:建造者模式

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

作者: 江湖再见2024 | 来源:发表于2017-03-23 15:21 被阅读41次

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

关于作者

郭孝星,程序员,吉他手,主要从事Android平台基础架构方面的工作,欢迎交流技术方面的问题,可以去我的Github提issue或者发邮件至guoxiaoxingse@163.com与我交流。

文章目录: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源码分析系列文章中会做进一步的详尽分析。

相关文章

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

    Android系统编程思想篇:建造者模式 关于作者 郭孝星,程序员,吉他手,主要从事Android平台基础架构方面...

  • 建造者模式(部件构造)

    目录 建造者模式的理念 从 POJO 到建造者模式的思考 怎么来实现建造者模式 建造者模式在Android源码中的...

  • Android系统编程思想篇:单例模式

    Android系统编程思想篇:单例模式 关于作者 郭孝星,程序员,吉他手,主要从事Android平台基础架构方面的...

  • Android 中的建造者模式

    Android 中的建造者模式 概述 建造者模式(Builder Pattern)也叫生成器模式,其定义如下:se...

  • Android面试知识整理-android基础知识

    Android面试知识整理-Java篇 1.okhttp原理: 运用建造者模式,Dispatcher运用线程池,底...

  • Android学习路线

    Google android开发者网站培训文档 java编程思想 设计模式和架构设计 framework

  • Builder Pattern in Java

    建造者模式:建造者模式定义建造者模式应用场景实现案例Jdk中的建造者模式建造者模式的优点建造者模式的缺点 建造者模...

  • 建造者模式

    Android中建造者模式使用最普遍的就是Dialog。下面这个Dialog采用建造者模式,富文本等。 1.下面进...

  • android中常见的设计模式有哪些?

    建造者模式 建造者模式最明显的标志就是Build类,而在Android中最常用的就是Dialog的构建,Notif...

  • Android -建造者模式

    今天我们来聊一聊我们经常用到的模式-建造者模式(Builder Pattern). 一: 1.什么是建造者模式?...

网友评论

      本文标题:Android系统编程思想篇:建造者模式

      本文链接:https://www.haomeiwen.com/subject/eeaznttx.html