美文网首页
面向面试学习之设计模式:建造者模式

面向面试学习之设计模式:建造者模式

作者: you的日常 | 来源:发表于2020-12-13 12:32 被阅读0次

每种设计模式的出现,都是为了解决一些编程不够优雅的问题,建造者模式也是这样。

维基百科解释是:建造者模式 Builder Pattern,又名生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

先上一个例子

借用并改造下 Effective Java 中给出的例子:每种食品包装上都会有一个营养成分表,每份的含量、每罐的含量、每份卡路里、脂肪、碳水化合物、钠等,还可能会有其他 N 种可选数据,大多数产品的某几个成分都有值,该如何定义营养成分这个类呢?

重叠构造器

因为有多个参数,有必填、有选填,最先想到的就是定义多个有参构造器:第一个构造器只有必传参数,第二个构造器在第一个基础上加一个可选参数,第三个加两个,以此类推,直到最后一个包含所有参数,这种写法称为重叠构造器,有点像叠罗汉。还有一种常见写法是只写一个构造函数,包含所有参数。

代码如下:

public class Nutrition {
    private int servingSize;// required
    private int servings;// required
    private int calories;// optional
    private int fat;// optional
    private int sodium;// optional
    private int carbohydrate;// optional

    public Nutrition(final int servingSize, final int servings) {
        this(servingSize, servings, 0, 0, 0, 0);
    }

    public Nutrition(final int servingSize, final int servings, final int calories) {
        this(servingSize, servings, calories, 0, 0, 0);
    }

    public Nutrition(final int servingSize, final int servings, final int calories, final int fat) {
        this(servingSize, servings, calories, fat, 0, 0);
    }

    public Nutrition(final int servingSize, final int servings, final int calories, final int fat, final int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public Nutrition(final int servingSize, final int servings, final int calories, final int fat, final int sodium, final int carbohydrate) {
        this.servingSize = servingSize;
        this.servings = servings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }

    // getter
}

这种写法还可以有效解决参数校验,只要在构造器中加入参数校验就可以了。

如果想要初始化实例,只需要 new 一下就行:

new Nutrition(100, 50, 0, 35, 0, 10)

这种写法,不够优雅的地方是,当 calories 和 sodium 值为 0 的时候,也需要在构造函数中明确定义是 0,示例中才 6 个参数,也能勉强接受。但是如果参数达到 20 个呢?可选参数中只有一个值不是 0 或空,写起来很好玩了,满屏全是 0 和 null 的混合体。

还有一个隐藏缺点,那就是如果同类型参数比较多,比如上面这个例子,都是 int 类型,除非每次创建实例的时候仔细对比方法签名,否则很容易传错参数,而且这种错误编辑器检查不出来,只有在运行时会出现各种诡异错误,排错的时候不知道要薅掉多少根头发了。

想要解决上面两个问题,不难想到,可以通过 set 方法一个个赋值就行了。

set 方式赋值

既然构造函数中放太多参数不够优雅,还有缺点,那就换种写法,构造函数只保留必要字段,其他参数的赋值都用 setter 方法就行了。

代码如下:

public class Nutrition {
    private final int servingSize;// required
    private final int servings;// required
    private int calories;// optional
    private int fat;// optional
    private int sodium;// optional
    private int carbohydrate;// optional

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

    // getter and setter
}

这样就可以解决构造函数参数太多、容易传错参数的问题,只在需要的时候 set 指定参数就行了。

如果没有特殊需求,到这里可以解决大部分问题了。

但是需求总是多变的,总会有类似“五彩斑斓的黑”这种奇葩要求:

  1. 如果必填参数比较多,或者大部分参数是必填参数。这个时候这种方式又会出现重叠构造器那些缺点。
  2. 如果把所有参数都用 set 方法赋值,那又没有办法进行必填项的校验。
  3. 如果非必填参数之间有关联关系,比如上面例子中,脂肪 fat 和碳水化合物 carbohydrate 有值的话,卡路里 calories 一定不会为 0。但是使用现在这种设计思路,属性之间的依赖关系或者约束条件的校验逻辑就没有地方定义了。
  4. 如果想要把 Nutrition 定义成不可变对象的话,就不能使用 set 方法修改属性值。

这个时候就该祭出今天的主角了。

建造者模式

相关文章

  • 面向面试学习之设计模式:建造者模式

    每种设计模式的出现,都是为了解决一些编程不够优雅的问题,建造者模式也是这样。 维基百科解释是:建造者模式 Buil...

  • 一篇文章搞懂设计模式

    目录 面向对象的七种设计原则建造者模式命令模式享元模式模板方法模式责任链模式建造者模式原型模式观察者模式策略模式与...

  • Android中涉及的模式

    我的Java设计模式-建造者模式 我的Java设计模式-观察者模式 重学设计模式之单例模式

  • 设计模式之Builder建造者模式 代码初见

    设计模式之Builder建造者模式 代码初见 测试 参考 想要看到更多玮哥的学习笔记、考试复习资料、面试准备资料?...

  • 设计模式之建造者模式

    设计模式之建造者模式 Intro 简介 建造者模式: 建造者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加...

  • 设计模式之建造者模式

    设计模式之建造者模式 1. 模式定义 建造者模式又可以成为生成器模式,它属于对象创建型模式。建造者模式将一个复杂对...

  • Javaの设计模式之建造者模式

    推荐阅读:《设计模式之禅》 今早早起,刚刚出炉,哈哈 BuilderPattern 设计模式之建造者模式 Demo...

  • PHP完整实战23种设计模式

    前言 设计模式是面向对象的最佳实践 实战 PHP实战创建型模式 单例模式 工厂模式 抽象工厂模式 原型模式 建造者...

  • 设计模式之建造者模式

    设计模式之建造者模式 建造者模式 属于 创建型模式,提供一种创建对象的最佳方式。 创建型模式 指不是直接使用ne...

  • Retrofit

    Retrofit设计模式 动态代理,装饰模式,建造者模式,抽象工厂模式,适配器模式 建造者模式创建Retrofit...

网友评论

      本文标题:面向面试学习之设计模式:建造者模式

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