建造者模式

 ̄綄美尐妖づ 提交于 2020-03-08 20:21:50

建造者模式

定义:

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

作用:

在用户不知道对象的建造过程和细节的情况下,可以直接创建复杂的对象

优点:

  • 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必要知道产品内部组成的细节
  • 将复杂产品的创建步骤分截在不同的方法中,使得创建过程更加清晰
  • 具体的建造者之间使相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合”开闭原则“。

缺点:

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

应用场景:

  • 需要生成的产品对象有复杂的内部结构,这些产品对象具有共性
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
  • 适合于一个具有较多的零件(属性)的产品(对象)的创建过程

1、测试案例一

先设想一个场景:工程师修建房子,并且他知道他需要做的工作是打地基、铺电线、打钢筋、粉刷墙壁以及最终得到房子,但是他不会自己做,这个具体的事情由工人完成,他只是负责指挥工人完成相应的工作。

这段话里面含有四个对象:

  • 工程师:建造出来的房子、口头上的命令工作
  • 抽象的工作(口头上的工作):名义上的建造房子需要做的四项工作、得到房子
  • 工人:真实完成的四项工作、建造出来的产品
  • 修建出来的房子:房子是由四个工作累积起来的

在这里插入图片描述

  1. 抽象的工作类:Buider.java

    package pers.mobian.buider.demo01;
    
    public abstract class Buider {
        abstract void buiderA(); //地基
        abstract void buiderB(); //钢筋工程
        abstract void buiderC(); //铺电线
        abstract void buiderD(); //粉刷
    
        //完工:得到具体的产品
        abstract Product getProduct();
    }
    
  2. 工人类:Worker.java

    package pers.mobian.buider.demo01;
    
    //具体的建造者:工人
    public class Worker extends Buider{
        private Product product;
    
        public Worker() {
            product = new Product();
        }
    
        @Override
        void buiderA() {
            product.setBuiderA("地基");
            System.out.println("地基");
        }
    
        @Override
        void buiderB() {
            product.setBuiderB("钢筋工程");
            System.out.println("钢筋工程");
    
        }
    
        @Override
        void buiderC() {
            product.setBuiderC("铺电线");
            System.out.println("铺电线");
    
        }
    
        @Override
        void buiderD() {
            product.setBuiderD("粉刷");
            System.out.println("粉刷");
    
        }
    
        @Override
        Product getProduct() {
            return product;
        }
    }
    
  3. 修建出来的房子:Product.java

    package pers.mobian.buider.demo01;
    
    public class Product {
        private String buiderA;
        private String buiderB;
        private String buiderC;
        private String buiderD;
    
        @Override
        public String toString() {
            return "Product{" +
                    "buiderA='" + buiderA + '\'' +
                    ", buiderB='" + buiderB + '\'' +
                    ", buiderC='" + buiderC + '\'' +
                    ", buiderD='" + buiderD + '\'' +
                    '}';
        }
    
        public String getBuiderA() {
            return buiderA;
        }
    
        public void setBuiderA(String buiderA) {
            this.buiderA = buiderA;
        }
    
        public String getBuiderB() {
            return buiderB;
        }
    
        public void setBuiderB(String buiderB) {
            this.buiderB = buiderB;
        }
    
        public String getBuiderC() {
            return buiderC;
        }
    
        public void setBuiderC(String buiderC) {
            this.buiderC = buiderC;
        }
    
        public String getBuiderD() {
            return buiderD;
        }
    
        public void setBuiderD(String buiderD) {
            this.buiderD = buiderD;
        }
    }
    
  4. 工程师:Director.java

    package pers.mobian.buider.demo01;
    
    //指挥:核心,负责只会构建一个工程,工程如果构建,
    public class Director {
        //指挥工人,按照顺序修建房子
        public Product build(Buider buider) {
            buider.buiderA();
            buider.buiderB();
            buider.buiderC();
            buider.buiderD();
            return buider.getProduct();
        }
    }
    
  5. 验房,即测试类:Test.java

    package pers.mobian.buider.demo01;
    
    public class Test {
        public static void main(String[] args) {
            //叫对应的工程师
            Director director = new Director();
            //工程师去指挥对应的工人
            Product build = director.build(new Worker());
            //打印输出修好了的房子
            System.out.println(build.toString());
        }
    }
    
  6. 结果

    地基
    钢筋工程
    铺电线
    粉刷
    Product{buiderA='地基', buiderB='钢筋工程', buiderC='铺电线', buiderD='粉刷'}
    

总结:测试类只需要简单的调用工程师类,具体工程师去叫哪个工人,得出什么样的产品,测试类不需要关心。并且,用此方法实现的话,代码有很强的可扩展性。需要不同的产品只需要让工程师调用不同的工人即可。

但是有时候,我们需要简化的系统结构,可以把Director和抽象类进行一个结合。通过静态内部类方式实现零件无序装配构造,此方式更加的灵活且符合规定。内部有复杂对象的默认实现,使用时间可以根据用户需求自由定义更改内容,并且无需修改具体的构造方式。就饿能够生产出不同的复杂产品。

例如:你去快餐,服务员(具体的建造者Worker)可以随意搭配任意几种产品(零件Builder)组成一套套餐(产品Product),然后出售给客户。比第一种方式少了指挥者,主要是因为第二种方式把指挥者交给了用户自己来操作,使得产品更加灵活。


2、测试案例二

设想一个场景:某天客户(Test)去一个餐馆吃饭,但是他却不知道改吃什么,于是就点了一个他们店的经典套餐(默认菜单)。第二天他又去,但是这次他只想喝白开水,于是他就叫服务员(Worker),让他给他来四杯白开水,服务员问了一下后厨(Builder),后厨说还有白开水,于是服务员就修改了菜单,然后就上了四倍白开水。

这段话里面含有四个对象:

  • 客户:叫服务员、得到菜
  • 后厨(口头上的工作):询问是否还有菜、做菜
  • 服务员:负责修改菜单、上菜
  • 菜单:菜单上是经典套餐、菜单上是自己点的水

在这里插入图片描述

  1. 后厨:Builder.java

    package pers.mobian.buider.demo02;
    
    public abstract class Builder {
        abstract Builder builderA(String msg);
    
        abstract Builder builderB(String msg);
    
        abstract Builder builderC(String msg);
    
        abstract Builder builderD(String msg);
    
        abstract Product getProduct();
    }
    
  2. 菜单:Product.java

    package pers.mobian.buider.demo02;
    
    public class Product {
        private String builderA = "青椒肉丝";
        private String builderB = "豆腐汤";
        private String builderC = "白米饭";
        private String builderD = "咸菜";
    
    
    
        public String getBuilderA() {
            return builderA;
        }
    
        public void setBuilderA(String builderA) {
            this.builderA = builderA;
        }
    
        public String getBuilderB() {
            return builderB;
        }
    
        public void setBuilderB(String builderB) {
            this.builderB = builderB;
        }
    
        public String getBuilderC() {
            return builderC;
        }
    
        public void setBuilderC(String builderC) {
            this.builderC = builderC;
        }
    
        public String getBuilderD() {
            return builderD;
        }
    
        public void setBuilderD(String builderD) {
            this.builderD = builderD;
        }
    
        //打印具体的产品
        @Override
        public String toString() {
            return "Product{" +
                    "builderA='" + builderA + '\'' +
                    ", builderB='" + builderB + '\'' +
                    ", builderC='" + builderC + '\'' +
                    ", builderD='" + builderD + '\'' +
                    '}';
        }
    }
    
  3. 服务员:Worker.java

    package pers.mobian.buider.demo02;
    
    public class Worker  extends Builder{
    
        private Product product;
    
        public Worker() {
            product = new Product();
        }
    
        @Override
        Builder builderA(String msg) {
            product.setBuilderA(msg);
            return this;
        }
    
        @Override
        Builder builderB(String msg) {
            product.setBuilderB(msg);
            return this;
        }
    
        @Override
        Builder builderC(String msg) {
            product.setBuilderC(msg);
            return this;
        }
    
        @Override
        Builder builderD(String msg) {
            product.setBuilderD(msg);
            return this;
        }
    
        @Override
        Product getProduct() {
            return product;
        }
    }
    
  4. 用户测试类:Test.java

    package pers.mobian.buider.demo02;
    
    //类似于之前是工程师Directer
    public class Test {
        public static void main(String[] args) {
            Worker worker = new Worker();
            //默认套餐
            System.out.println(worker.getProduct().toString());
            //用户修改以后的套餐,此处可以使用链式编程,直接修改好一整个菜单
            Product product = worker.builderA("白开水1号").builderB("白开水2号").builderC("白开水3号").builderD("白开水4号").
                    getProduct();
            System.out.println(product.toString());
    
    
        }
    }
    
  5. 结果:

    Product{builderA='青椒肉丝', builderB='豆腐汤', builderC='白米饭', builderD='咸菜'}
    Product{builderA='白开水1号', builderB='白开水2号', builderC='白开水3号', builderD='白开水4号'}
    

总结:此方式比第一种更加的灵活。


3、与抽象工厂做比较

  • 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族
  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。
  • 如果将抽象工厂模式看出汽车而配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件得组装可以返回一辆完整得汽车。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!