设计模式学习(四):建造者模式

设计模式,学习,建造,模式 · 浏览次数 : 362

小编点评

**设计模式学习(四):建造者模式** **什么是建造者模式?** 建造者模式是一种创建型设计模式,用于在对一个实体类进行属性的 get 或 set 的时候,通过封装一些常用的构造方法来简化实体类的构造。 **建造器模式的优点:** * 降低了代码复杂性。 * 简化了属性设置。 * 提高了代码可读性。 **建造器模式的缺点:** * 建造器类可能过于复杂。 * 建造器类可能难以测试。 **建造器模式的应用:** 建造器模式适用于创建具有多个构造参数的实体类。例如: * **Effective Java 中的 `NutritionFacts` 实体类** **建造器模式的示例:** ```java public class Builder { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; } public Builder sodium(int val) { sodium = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } ``` **其他设计模式与建造器模式的比较:** | 特征 | 建造者模式 | 设计模式 | |---|---|---| | 构造方法数量 | 1个 | 多个 | | 建造器类复杂性 | 较低 | 较高 | | 建造器可测试性 | 较低 | 较高 | | 应用场景 | 创建具有多个构造参数的实体类 | 创建具有复杂构造参数的实体类 |

正文

设计模式学习(四):建造者模式

作者:Grey

原文地址:

博客园:设计模式学习(四):建造者模式

CSDN:设计模式学习(四):建造者模式

建造者模式

建造者模式是创建型模式。

我们在对一个实体类进行属性的 get 或 set 的时候,可以通过封装一些常用的构造方法来简化实体类的构造。

比如 Effective Java 中举到到这个例子

// Effective Java 3th examples
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories      = 0;
        private int fat           = 0;
        private int sodium        = 0;
        private int carbohydrate  = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

        public Builder calories(int val) { 
            calories = val;  
            return this;
        }

        public Builder fat(int val) { 
           fat = val;   
           return this;
        }

        public Builder sodium(int val) { 
           sodium = val;  
           return this; 
        }

        public Builder carbohydrate(int val) { 
           carbohydrate = val;  
           return this; 
        }

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

    private NutritionFacts(Builder builder) {
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

其中 Builder 就是一个内部类,用于构造 NutritionFacts 的必要信息,外部调用 NutritionFacts 的构造方法时候,可以这样使用:

NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();

image

构造器模式也适用于类层次结构。抽象类有抽象的 Builder ,具体类有具体的 Builder 。Effective Java中还有一个例子, 假设我们抽象出一个披萨类,各种各样的披萨均可以继承披萨这个抽象类来实现自己的具体类型的披萨。

Pizza抽象类如下:

import java.util.*;

// Effective Java 3th examples
public abstract class Pizza {
    public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}
    final Set<Topping> toppings;
  
    abstract static class Builder<T extends Builder<T>> {
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }
  
        abstract Pizza build();
  
        // Subclasses must override this method to return "this"
        protected abstract T self();
    }

    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone(); // See Item 50
    }
}

其中的 Builder 方法是抽象的,所以子类需要实现具体的 Builder 策略,

一种披萨的具体实现 NyPizza

import java.util.Objects;

public class NyPizza extends Pizza {
    public enum Size {SMALL, MEDIUM, LARGE}

    private final Size size;

    public static class Builder extends Pizza.Builder<Builder> {
        private final Size size;

        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        @Override
        public NyPizza build() {
            return new NyPizza(this);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}

另一种披萨的具体实现 Calzone

public class Calzone extends Pizza {
    private final boolean sauceInside;

    public static class Builder extends Pizza.Builder<Builder> {
        private boolean sauceInside = false; // Default

        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        @Override
        public Calzone build() {
            return new Calzone(this);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }

    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }
}

我们在具体调用的时候,可以通过如下方式:

NyPizza pizza = new NyPizza.Builder(SMALL).addTopping(SAUSAGE).addTopping(ONION).build();
Calzone calzone = new Calzone.Builder().addTopping(HAM).sauceInside().build();

实际应用有非常多,很多组件都提供这样的构造方式,比如 OkHttp Client 的构造方法:

public static OkHttpClient create(long connectTimeOut) {
        return new OkHttpClient().newBuilder().connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT)).connectTimeout(connectTimeOut, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).retryOnConnectionFailure(true).followRedirects(true).followSslRedirects(true).hostnameVerifier((s, sslSession) -> true).cookieJar(new CookieJar() {
            private List<Cookie> cookies;

            @Override
            public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                this.cookies = cookies;
            }

            @Override
            public List<Cookie> loadForRequest(HttpUrl url) {
                if (cookies != null) {
                    return cookies;
                }
                return Collections.emptyList();
            }
        }).build();
    }

建造者模式的主要应用

  • JDK 中的 Calender
Calendar calendar = new Calendar.Builder().build();
  • MyBatis 中 CacheBuilder.build()SqlSessionFactoryBuilder.build()

  • Spring 中 BeanDefinitionBuilder.getBeanDefinition()方法

UML 和 代码

UML 图

代码

更多

设计模式学习专栏

参考资料

与设计模式学习(四):建造者模式相似的内容:

设计模式学习(四):建造者模式

设计模式学习(四):建造者模式 作者:Grey 原文地址: 博客园:设计模式学习(四):建造者模式 CSDN:设计模式学习(四):建造者模式 建造者模式 建造者模式是创建型模式。 我们在对一个实体类进行属性的 get 或 set 的时候,可以通过封装一些常用的构造方法来简化实体类的构造。 比如 Ef

设计模式学习(十):门面模式

设计模式学习(十):门面模式 作者:Grey 原文地址: 博客园:设计模式学习(十):门面模式 CSDN:设计模式学习(十):门面模式 门面模式 门面模式是一种结构型模式。 门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。 假设建造一个房子需要有如下三个步骤: 第一步,和泥 第二

京东云开发者|软件架构可视化及C4模型:架构设计不仅仅是UML

软件系统架构设计的目标不在于设计本身,而在于架构设计意图的传达。图形化有助于在团队间进行高效的信息同步,但不同的图形化方式需要语义一致性和效率间实现平衡。C4模型通过不同的抽象层级来表达系统的静态结构,并提供了最小集的抽象建模元素,为设计人员提供了一种低认知负载、易于学习和使用的高效建模方式。

支持JDK19虚拟线程的web框架之四:看源码,了解quarkus如何支持虚拟线程

quarkus是如何支持虚拟线程的呢?今天咱们一起来阅读quarkus源码,学习从框架开发视角去添加新特性,除了开阔眼界,也为为自己的设计能力提升增加有效的参考信息

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

quarkus是如何支持虚拟线程的呢?今天咱们一起来阅读quarkus源码,学习从框架开发视角去添加新特性,除了开阔眼界,也为为自己的设计能力提升增加有效的参考信息

设计模式学习(二)工厂模式——抽象工厂模式+注册表

目录前言使用简单工厂改进使用注册表改进参考文章 前言 在上一篇文章中我们提到了抽象工厂模式初版代码的一些缺点:①客户端违反开闭原则②提供方违反开闭原则。本文将针对这两点进行讨论 使用简单工厂改进 对于缺点①,我们可以使用简单工厂的思路来改进抽象工厂的初版代码。对于上一篇文章中的例子,我们去除Came

设计模式学习(二)工厂模式——抽象工厂模式

目录背景抽象工厂模式优点与缺点参考文章 背景 现在我需要开发一个相机操作模块,它可能在Windows下运行,也可能在Linux下运行。由于在厂家提供的SDK中,Windows下的SDK和Linux下的SDK是有区别的,因此对于一个品牌的相机,我们要创建两个类去封装这两个不同平台下的API。 我们先使

设计模式学习(二)工厂模式——工厂方法模式+注册表

目录工厂方法模式的瑕疵注册表 工厂方法模式的瑕疵 在前一篇笔记中我们介绍了工厂方法模式,示例的类图如下: 考虑一种情况:现在要在程序运行时,根据外部资源,动态的实例化对象。也就是说在编译期我们无法知道要实例化的对象的类型。因此在实例化的过程中,就需要加以判断。 例如,在我的例子中,要根据连接到主机的

设计模式学习(二):单例模式

设计模式学习(二):单例模式 作者:Grey 原文地址: 博客园:设计模式学习(二):单例模式 CSDN:设计模式学习(二):单例模式 单例模式 单例模式是创建型模式。 单例的定义:“一个类只允许创建唯一一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。”定

设计模式学习(三):工厂模式

设计模式学习(三):工厂模式 作者:Grey 原文地址: 博客园:设计模式学习(三):工厂模式 CSDN:设计模式学习(三):工厂模式 工厂模式 工厂模式是创建型模式,工厂模式分为:简单工厂,工厂方法和抽象工厂三种类型。 简单工厂 这个模式很简单,比如我们需要制造不同类型的鼠标,我们只需要创建一个鼠