设计模式[4]-建造者模式

代码:https://gitee.com/Aes_yt/design-pattern

建造者模式

建造者模式是将一个复杂对象,解构为多个简单的对象,然后一步一步慢慢构造成原对象。

建造者模式主要包括四种角色:
  • 抽象建造者:具有产品的多个子部件的抽象接口,最终可以返回完整产品
  • 具体建造者:对抽象建造者的实现,有多个子部件的具体生成方法
  • 产品角色:一个复杂对象,由建造者来构造它的不同子部件。
  • 指挥者:调用建造者对产品子部件的构建,可以决定创建子部件的顺序
例子

如果我们要创建一个产品角色:一瓶瓶装饮料,它是由瓶身,液体,商标组成,现在我们要创建一瓶可乐饮料和一瓶雪碧饮料,那么我们就可以用建造者模式来实现这个需求。

  • 抽象建造者:Builder,拥有构造产品角色部件的三个方法和返回完整Beverage 对象的方法。
  • 具体建造者:ColaBuilder和SpriteBuilder,各自实现Builder的方法。
  • 产品角色:Beverage 饮料类,包含bottler,liquid,label对象。
  • 指挥者:Director,装载不同Builder,按一定顺序创建bottler,liquid,label对象,最终返回完整Beverage对象。

image-20211216233023185

产品角色:饮料类:Beverage

@Data
public class Beverage {
    private String bottle;
    private String liquid;
    private String label;

    @Override
    public String toString() {
        return "Beverage{" +
                "bottle='" + bottle + '\'' +
                ", liquid='" + liquid + '\'' +
                ", label='" + label + '\'' +
                '}';
    }
}

抽象建造者:Builder:

public abstract class Builder {
    protected Beverage beverage = new Beverage();

    /**
     * 构建瓶子对象
     */
    abstract void builderBottle();

    /**
     * 构建液体对象
     */
    abstract void builderLiquid();

    /**
     * 构建商标对象
     */
    abstract void builderLabel();

    /**
     * 构建饮料对象
     */
    abstract Beverage build();
}

具体建造者:

每种具体产品都实现具体的建造者。

可乐建造者:ColaBuilder:

public class ColaBuilder extends Builder {
    @Override
    public void builderBottle() {
        beverage.setBottle("透明瓶子");
    }

    @Override
    public void builderLiquid() {
        beverage.setLiquid("黑色汽水");
    }

    @Override
    public void builderLabel() {
        beverage.setLabel("Cola~");
    }

    @Override
    public Beverage build() {
        return beverage;
    }
}

雪碧建造者:SpriteBuilder:

public class SpriteBuilder extends Builder{
    @Override
    public void builderBottle() {
        beverage.setBottle("绿色瓶子");
    }

    @Override
    public void builderLiquid() {
        beverage.setLiquid("白色汽水");
    }

    @Override
    public void builderLabel() {
        beverage.setLabel("Sprite~");
    }

    @Override
    public Beverage build() {
        return beverage;
    }
}

指挥者:Director:

public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    /**
     * 指挥者决定构造的顺序,最后返回完整的对象
     */
    public Beverage construct() {
        this.builder.builderBottle();
        this.builder.builderLiquid();
        this.builder.builderLabel();
        return this.builder.build();
    }
}

测试:

class DirectorTest {
    @Test
    void construct() {
        Director director = new Director(new ColaBuilder());
        Beverage beverage = director.construct();
        System.out.println(beverage);

        director = new Director(new SpriteBuilder());
        beverage = director.construct();
        System.out.println(beverage);
    }
}

输出:

Beverage{bottle='透明瓶子', liquid='黑色汽水', label='Cola~'}
Beverage{bottle='绿色瓶子', liquid='白色汽水', label='Sprite~'}
分析

建造者模式可以对子部件的模块的创建进行控制,最终再获得完整的产品。这和工厂模式的侧重点不同,工厂模式注重完整对象的创建过程,建造者模式注重零件的组装过程。而且建造者可以在指挥者角色中控制子部件的组装顺序,顺序不同,最终组装的产品也有可以不同,这也是它的特点。

拓展

用建造者模式实现链式赋值:

以上面的例子Beverage为例,如果我们想直接新建一个Beverage实例并给他赋值,我们的代码应该是:

    void test() {
        Beverage beverage = new Beverage();
        beverage.setLabel("标签");
        beverage.setLiquid("液体");
        beverage.setBottle("瓶子");
        System.out.println(beverage);
    }

接下来,我们利用建造者模式实现链式赋值。

我重新建了一个BeverageChain类来展示这个效果。

首先先去掉三个属性的get和set方法,然后创建私有的构造方法,接收的参数就是建造者对象,最后创建一个内部类当作建造者,用来建造三个参数,为了使用方便,变量名和方法名都是用同样的单词,最后在build方法,创建一个BeverageChain类返回完成建造。

public class BeverageChain {
    private String bottle;
    private String liquid;
    private String label;

    private BeverageChain(Builder builder) {
        this.bottle = builder.bottle;
        this.liquid = builder.liquid;
        this.label = builder.label;
    }

    @Override
    public String toString() {
        return "BeverageChain{" +
                "bottle='" + bottle + '\'' +
                ", liquid='" + liquid + '\'' +
                ", label='" + label + '\'' +
                '}';
    }

    public static class Builder {
        private String bottle;
        private String liquid;
        private String label;

        public Builder() {
        }

        public Builder bottle(String bottle) {
            this.bottle = bottle;
            return this;
        }

        public Builder liquid(String liquid) {
            this.liquid = liquid;
            return this;
        }

        public Builder label(String label) {
            this.label = label;
            return this;
        }

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

测试:

@Test
void chained() {
    BeverageChain.Builder builder = new BeverageChain.Builder();
    BeverageChain beverage =  builder.bottle("瓶子").label("标签").liquid("液体").build();
    System.out.println(beverage);
}

输出:

BeverageChain{bottle='瓶子', liquid='液体', label='标签'}
posted @ 2024-08-23 11:05  Aeons  阅读(5)  评论(0编辑  收藏  举报