Java设计模式 | 建造者模式解析与实战

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Java设计模式 | 建造者模式解析与实战

概述

**因为一个复杂的对象有很多大量组成部分,
如汽车,有车轮、方向盘、发动机,还有各种小零件等,
如何将这些部件装配成一辆汽车,这个装配过程很漫长,也很复杂,
对于这种情况,
为了在构建过程对外部隐藏实现细节
就可以使用Builder模式产品的构建过程部件组装过程分离,
使得产品的构建过程部件组装过程都可以自由扩展,
两者之间的耦合降到最低
【一个产品的构建过程包括多个部件组装过程】**

定义

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

使用场景

  • **(1)相同的方法,不同的执行顺序,产生不同的事件结果时。

(2)多个部件或零件,
都可以装配到一个对象中,但是产生的运行结果又不相同时。
(3)产品类非常复杂
或者
产品类中部件组装过程调用顺序不同产生了不同的作用
这个时候使用建造者模式非常合适。
(4)当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时!!!!**

UML类图

  • **角色介绍:

● Director——统一组装过程。
定义一系列的 组装统筹方法,
一个 组装统筹方法里边 包含若干个部件组装方法;
方便某方面的组装;

● Builder——抽象Builder类,
规范产品的组建,
一般是由子类实现具体的组建过程;
【以上两个成分在实际操作中经常会省略!!!!】

● Product产品类——产品的抽象类;

● ConcreteBuilder——具体的Builder类;包含具体的组装过程;**

实现案例【注:两种实现形式】

**建造者模式个人觉得,其实可以有两种实现过程;
第一种是,**

  • 把部件组装方法【属性配置方法】定义在产品类中;!!!!!
  • **抽象产品类【三个元素:属性、两种方法的声明、实现】

定义好一类产品需要的属性[1]
以及需要的组装方法[2、3]
【包括抽象具体的两种,
具体的是这类产品的共性组装方法,所有分化产品都一样,无需修改;[2]
抽象的是个性比较高 留给具体子类具体实现 [3]】;

具体产品类继承抽象产品类,根据个性实现抽象组装方法;
【实际开发中,
可以在抽象产品类中或者具体产品类中,
对属性配置好默认值
防止空指针报错】**

  • **Builder类中,只是负责拿到一个产品类实例,

然后编写很多组装方法
组装方法中只是使用产品类实例调用了产品类自己的组装方法而已;
抽象Builder类只声明需要的组装方法;!!!!!!!!

具体Builder类面向具体产品类
继承抽象Builder类的同时,
拿到一个对应的具体产品类实例作为自己的全局成员,[1]
实现所有组装方法,[2]
组装方法中使用具体产品类实例调用了产品类自己的组装方法即可;
最后create()或者build()返回一个产品类实例,构造完毕;[3]**

  • **Director一般可以省略掉,

即整个模式有四种类文件——抽象/具体产品类抽象/具体Builder类**

**个人心得:
这种形式存在抽象产品类抽象Builder类
可以解耦抽象一些逻辑,

适用于具体产品类有两个或两个以上的较大规模的开发;**

**如果具体产品类在整个开发过程中确定只有一个,
那就用不着那么多花里胡俏的抽象类了,
完全可以直接去掉抽象产品类抽象Builder类
只剩下具体产品类具体Builder类
即简化版的第二种实现方式;

下面先看第一种实现案例:**

//产品抽象类
public abstract class Computer {
    protected String mBoard; 
    protected String mDisplay; 
    protected String mOS;
    
    protected Computer() { }
    // 设置 CPU 核心数
    public void setBoard(String board) {
        mBoard = board; 
    }
    // 设置内存
    public void setDisplay(String display) {
        mDisplay = display; 
    }
    // 设置操作系统
    public abstract void setOS();
    
    @Override
    public String toString() {
        return "Computer [mBoard=" + mBoard + ", mDisplay=" + mDisplay + ", mOS=" + mOS + "]";
    }
}

----------------------------------------------------------------------------------
//具体的 Computer 类,Macbook 
public class Macbook extends Computer {
    protected Macbook() {
    }

    @Override
    public void setOS() {
        mOS = "Mac OS X 10.10";
    }
}

----------------------------------------------------------------------------------

//抽象 Builder 类
public abstract class Builder {
    // 设置主机
    public abstract void buildBoard(String board);

    // 设置显示器
    public abstract void buildDisplay(String displau);

    // 设置操作系统
    public abstract void buildOS();

    // 创建 ComputerÏ
    public abstract Computer create();
}


----------------------------------------------------------------------------------
//具体的 Builder 类,
public class MacbookBuilder extends Builder {
    private Computer mComputer = new Macbook();

    @Override
    public void buildBoard(String board) {
        mComputer.setBoard(board);
    }

    @Override
    public void buildDisplay(String display) {
        mComputer.setDisplay(display);
    }

    @Override
    public void buildOS() {
        mComputer.setOS();
    }

    @Override
    public Computer create() {
        return mComputer;
    }
}
----------------------------------------------------------------------------------

//Director 类,负责构造 Computer 
public class Director {
    Builder mBuilder = null;

    /**
     * @param builder
     */
    public Director(Builder builder) {
        mBuilder = builder;
    }

    /**
     * 构建对象
     */
    public void construct(String board, String display) {
        mBuilder.buildBoard(board);
        mBuilder.buildDisplay(display);
        mBuilder.buildOS();
    }
}
----------------------------------------------------------------------------------

//测试代码 
public class Test {
    public static void main(String[] args) { // 构建器
        Builder builder = new MacbookBuilder();
        // Director
        Director pcDirector = new Director(builder);
        // 封装构建过程, 4 核, 内存 2GB, Mac 系统 
        pcDirector.construct("英特尔主板","Retina 显示器");
        // 构建电脑, 输出相关信息
        System.out.println("Computer Info : " + builder.create().toString());
    }
}
  • **简化版的第二种实现方式;

如果具体产品类在整个开发过程中确定只有一个,
那就用不着那么多花里胡俏的抽象类了,
完全可以直接去掉抽象产品类和抽象Builder类,
只剩下具体产品类具体Builder类;**

  • **另外方才第一种方法写了很多次配置方法【产品类、抽象类都写了】,

这里只需要在具体Builder类中写即可!!!!**

  • **具体Builder类

定义产品需要的部件属性,并在声明时初始化为默认值!![1]
构造方法设置为默认权限,只提供给具体产品类builder()调用[2]
编写组装方法,用于配置本类属性,注意return this;用于连缀调用;[3]
提供build()方法,把所有的部件属性赋给产品类构造器并调用它,返回一个产品实例;[4]**

  • **具体产品类

定义产品需要的部件属性;(构造方法赋值所有属性)[1]
提供public static builder(),返回一个具体Builder类实例;[2]
实现其他产品业务方法 [3 此部分无关构造了]**

案例来自项目GitHub
/**
 * <pre>
 *     desc   : 使用建造者模式,构建 RestClient!!!
 *              此类是建造者模式中,concreteBuilder部分
 * </pre>
 */
public class RestClientBuilder {
    //URL
    private  String mUrl = null;
    //参数
    private  static final WeakHashMap<String, Object> PARAMS = RestCreator.getParams();
    //回调
    private  IRequest mIRequest = null;
    private  ISuccess mISuccess = null;
    private  IFailure mIFailure = null;
    private  IError mIError = null;
    //请求体
    private  RequestBody mBody = null;
    //Loader
    private Context mContext = null;
    private LoaderStyle mLoaderStyle = null;
    //文件上传
    private File mFile = null;
    //文件下载用 变量
    private String mDownloadDir = null;//指定 下载文件 在本地sd卡的 目录名
    private String mExtension = null;
    private String mName = null;

    //除了 RestClient(同包内的类),不允许外部 直接new 创建!!!
    //这里没 声明权限,即使用 Java 的 默认权限,
    // 即 只有 本类+同包 可以访问!!!只有 同包内的子类可以继承!!!!!
    RestClientBuilder() {
    }

    /*
        下面是本建造者模式的 一系列组装方法
     */
    //觉得某个方法已经很完善了,不需要别人修改它,可以加上final,
    // 这样也可以让JVM进行优化(如,禁止重排序)
    public final RestClientBuilder url(String url) {
        this.mUrl = url;
        return this;
    }
    public final RestClientBuilder params(WeakHashMap<String, Object> params) {
        PARAMS.putAll(params);
        return this;
    }
    public final RestClientBuilder params(String key, Object value) {
        PARAMS.put(key, value);
        return this;
    }
    //文件上传
    public final RestClientBuilder file(File file) {
        this.mFile = file;
        return this;
    }
    public final RestClientBuilder file(String file) {
        this.mFile = new File(file);
        return this;
    }
    public final RestClientBuilder raw(String raw) {
        this.mBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), raw);
        return this;
    }
    //不用写 set什么什么 ,直接简单明了写个success、写个raw、写个params,
    // 中心突出,简洁明了
    public final RestClientBuilder success(ISuccess iSuccess) {
        this.mISuccess = iSuccess;
        return this;
    }
    public final RestClientBuilder failure(IFailure iFailure) {
        this.mIFailure = iFailure;
        return this;
    }
    public final RestClientBuilder error(IError iError) {
        this.mIError = iError;
        return this;
    }
    public final RestClientBuilder onRequest(IRequest iRequest) {
        this.mIRequest = iRequest;
        return this;
    }
    //Loader
    public final RestClientBuilder loader(Context context,LoaderStyle style) {
        this.mContext = context;
        this.mLoaderStyle = style;
        return this;
    }
    public final RestClientBuilder loader(Context context) {
        this.mContext = context;
        this.mLoaderStyle = LoaderStyle.BallClipRotatePulseIndicator;
        return this;
    }
    //文件下载
    public final RestClientBuilder name(String name) {
        this.mName = name;
        return this;
    }
    public final RestClientBuilder dir(String dir) {
        this.mDownloadDir = dir;
        return this;
    }
    public final RestClientBuilder extension(String extension) {
        this.mExtension = extension;
        return this;
    }

    /**
     * 最终方法,返回 构建组装 完毕的 RestClient
     * @return
     */
    public final RestClient build() {
        return new RestClient(mUrl, PARAMS,
                mDownloadDir, mExtension, mName,
                mIRequest, mISuccess, mIFailure,
                mIError, mBody,mFile, mContext,
                mLoaderStyle);
    }
}

------------------------------------------------------





/**
 * <pre>
 *     desc   : 使用建造者模式,构建 RestClient!!!
 *              此类是建造者模式中,具体产品类部分
 * </pre>
 */
public class RestClient {
    //URL
    private final String URL;
    //参数
    private  static final WeakHashMap<String, Object> PARAMS = RestCreator.getParams();
    //回调接口
    private final IRequest REQUEST;
    private final ISuccess SUCCESS;
    private final IFailure FAILURE;
    private final IError ERROR;
    //文件下载用 变量,注意,一般!!传入了前两个就不用传入NAME,传入NAME了就不用传入前两个
    private String DOWNLOAD_DIR;//指定 下载文件 在本地sd卡的 目录名
    private String EXTENSION;//文件后缀名
    private String NAME;//完整的文件名
    //请求体
    private final RequestBody BODY;
    //Loader
    private final LoaderStyle LOADER_STYLE;
    private final Context CONTEXT;
    //文件上传
    private final File FILE;

    public RestClient(String url,
                      Map<String, Object> params,
                      String downloadDir,
                      String extension,
                      String name,
                      IRequest request,
                      ISuccess success,
                      IFailure failure,
                      IError error,
                      RequestBody body,
                      File file,
                      Context context,
                      LoaderStyle loaderStyle) {
        this.URL = url;
        PARAMS.putAll(params);
        this.DOWNLOAD_DIR = downloadDir;
        this.EXTENSION = extension;
        this.NAME = name;
        this.REQUEST = request;
        this.SUCCESS = success;
        this.FAILURE = failure;
        this.ERROR = error;
        this.BODY = body;
        this.FILE = file;
        this.CONTEXT = context;
        this.LOADER_STYLE = loaderStyle;
    }

    public static RestClientBuilder builder() {
        return new RestClientBuilder();
    }

    //封装请求操作
    private void request(HttpMethod method) {
        //获取为 Retrofit 框架 准备的 接口对象实例!!!
        final RestService service = RestCreator.getRestService();

        //用来接请求操作
        Call<String> call = null;

        if (REQUEST != null) {
            REQUEST.onRequestStart();
        }

        //展示 Loading!!(请求开始时)
        // 对应的 关闭的话在 RequestCallBacks 中 实现(请求结束时关闭!!)
        if (LOADER_STYLE != null) {
            XiaoYunLoader.showLoading(CONTEXT, LOADER_STYLE);
        } else {
            XiaoYunLoader.showLoading(CONTEXT);
        }

        switch (method) {
            case GET:
                call = service.get(URL, PARAMS);
                break;
            case POST:
                call = service.post(URL, PARAMS);
                break;
            case POST_RAW:
                call = service.postRaw(URL, BODY);
                break;
            case PUT:
                call = service.put(URL, PARAMS);
                break;
            case PUT_RAW:
                call = service.putRaw(URL, BODY);
                break;
            case DELETE:
                call = service.delete(URL, PARAMS);
                break;
            case UPLOAD:
                final RequestBody requestBody =
                        RequestBody.create(MediaType.parse(MultipartBody.FORM.toString()),FILE);
                //以 Form 的方式 提交
                final MultipartBody.Part body =
                        MultipartBody.Part.createFormData("file", FILE.getName(),requestBody);
                call = service.upload(URL, body);
                break;
            default:
                break;
        }

        if (call != null) {
            //如果 call不空,说明 需要进行请求的操作和参数 已经设定完毕
            //这里是选enqueue() 进行 异步请求方式,执行请求
            call.enqueue(getRequestCallback());
        }
    }

    //返回一个 RequestCallBacks 实例
    private Callback<String> getRequestCallback() {
        return new RequestCallBacks(
                REQUEST,
                SUCCESS,
                FAILURE,
                ERROR,
                LOADER_STYLE
        );
    }

    /*
           提供给外部调用的操作封装方法!!
           所有调用 RestService 获取 Call 对象实例的 调用逻辑,以及 call 的请求执行逻辑,
           都是在 RestClient 这里完成的,只有 download 的 RestService调用以及 call 的请求执行,
           是跳转到 DownloadHandler 中完成的
     */
    //增删改查,依次如下
    public final void post() {
        //BODY 或者 PARAMS 为不为空,就看 RestClientBuilder 构建时有没有配置;
        // RestClientBuilder 构建时 有配置的 字段,则不空,否则默认为空

        if (BODY == null) {
            //如果 BODY 为空,即是 一般的 PARAMS post 方式
            request(HttpMethod.POST);
        } else {
            //如果 BODY 不空,那只能是 post原始数据 BODY !!
            if (!PARAMS.isEmpty()) {
                //如果 BODY 不空,那只能是 post原始数据 BODY,
                // 这种 post 情况的话,要求参数 PARAMS 必须为空!
                //如果参数 PARAMS 不空
                throw new RuntimeException("params must be null");
            }
            //如果参数 PARAMS 为空
            request(HttpMethod.POST_RAW);

        }
    }
    public final void delete() {
        request(HttpMethod.DELETE);
    }
    public final void put() {
        if (BODY == null) {
            //如果 BODY 为空,即是 一般的 PARAMS put 方式
            request(HttpMethod.PUT);
        } else {
            //如果 BODY 不空,那只能是 put原始数据 BODY !!
            if (!PARAMS.isEmpty()) {
                //如果 BODY 不空,那只能是 put原始数据 BODY,
                // 这种 put 情况的话,要求参数 PARAMS 必须为空!
                //如果参数 PARAMS 不空
                throw new RuntimeException("params must be null");
            }
            //如果参数 PARAMS 为空
            request(HttpMethod.PUT_RAW);
        }
    }
    public final void get() {
        request(HttpMethod.GET);
    }

    //文件上传
    public final void upload() {
        request(HttpMethod.UPLOAD);
    }

    //文件下载
    public final void download() {
        new DownloadHandler(URL, PARAMS,REQUEST, DOWNLOAD_DIR, EXTENSION, NAME,
                SUCCESS, FAILURE, ERROR)
                .handleDownload();
    }
}










参考:

  • 《Android源码设计模式解析与实战》
  • 慕课网
相关文章
|
3天前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
43 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
9天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
9天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
9天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
9天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
7天前
|
安全 API 数据安全/隐私保护
速卖通AliExpress商品详情API接口深度解析与实战应用
速卖通(AliExpress)作为全球化电商的重要平台,提供了丰富的商品资源和便捷的购物体验。为了提升用户体验和优化商品管理,速卖通开放了API接口,其中商品详情API尤为关键。本文介绍如何获取API密钥、调用商品详情API接口,并处理API响应数据,帮助开发者和商家高效利用这些工具。通过合理规划API调用策略和确保合法合规使用,开发者可以更好地获取商品信息,优化管理和营销策略。
|
8天前
|
Java 数据库连接 Spring
反射-----浅解析(Java)
在java中,我们可以通过反射机制,知道任何一个类的成员变量(成员属性)和成员方法,也可以堆任何一个对象,调用这个对象的任何属性和方法,更进一步我们还可以修改部分信息和。
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2
|
3月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
87 0
|
3月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
68 0

热门文章

最新文章

推荐镜像

更多