设计模式——建造者模式(使用director指挥者和不适用director结合代码分析)

【1】什么是建造者模式?

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

  • 建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

  • 将一个复杂的构建与其表示(本身)相分离,使得同样的构建过程可以创建不同的表示。现在建造者模式主要用来通过链式调用生成不同的配置。

【2】为什么需要建造者模式?

  • 案例引出建造者模式
    设计模式——建造者模式(使用director指挥者和不适用director结合代码分析)_第1张图片

  • 首先我们使用平常最容易想到的方法:
    UML类图如下:
    设计模式——建造者模式(使用director指挥者和不适用director结合代码分析)_第2张图片
    一个抽象类House,抽象出4个方法,其中build方法内部顺序调用其他的三个方法,客户端依赖具体的房子,来建造房屋。

  • 优缺点:

  • 优点是比较好理解,简单易操作。
  • 缺点:设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好.也就是说,这种设计方案,把产品(即:房子)和**创建产品的过程(即:建房子流程)**封装在一起,耦合性增强了。
  • 解决方案:将产品和产品建造过程解耦=>建造者模式.

建造者模式的作用:

  • 分离了部件的构造(由Builder来负责)和装配(由Director负责)。从而可以构造出复杂的对象 这个模式适用于:某个对象的构建过程复杂的情况。(装饰器的内容是非常丰富的,但有时我们为了简化代码量,将Director封装到Builder中,但这样其实违背了单一职责原则,并且增大了耦合
  • 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
  • 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

【3】建造者模式

  • 建造者模式的4个角色:
  • 注:经典的「建造者-指挥者」模式现在已经不太常用了,现在建造者模式主要用来通过链式调用生成不同的配置。
  • Product(产品角色):一个具体的产品对象。
  • Builder(抽象建造者):创建一个Product对象的各个部件指定的接口/抽象类。
  • ConcreteBuilder(具体建造者):实现接口,构建和装配各个部件。
  • Director(指挥者):构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
  • 建造者模式的原理UML类图:
    设计模式——建造者模式(使用director指挥者和不适用director结合代码分析)_第3张图片

给一张UML,你能用建造者模式设计出来吗?

设计模式——建造者模式(使用director指挥者和不适用director结合代码分析)_第4张图片

  • 产品类:
/**
 * 相当于产品
 */
public class Bike {
    //车架
    private String frame;
    //车座
    private String seat;

    public String getFrame() {
        return frame;
    }


    public void setFrame(String frame) {
        this.frame = frame;
    }

    public String getSeat() {
        return seat;
    }

    public void setSeat(String seat) {
        this.seat = seat;
    }
}
  • 抽象建造者
/**
 * 抽象层建造者
 */
public abstract class Builder {
        //子类复用
        protected Bike bike = new Bike();
        //子类来实现(创建)
        public abstract void frameBuild();
        public abstract void seatBuild();
        public abstract Bike createBike();
}
  • 两个具体建造者:
/**
 * 具体建造者
 */
public class MobikeBuilder extends Builder{

    @Override
    public void frameBuild() {
        bike.setFrame("铝合金");
        System.out.println("摩拜单车框架是"+bike.getFrame());
    }

    @Override
    public void seatBuild() {
        bike.setSeat("真皮");
        System.out.println("摩拜单车坐垫是"+bike.getSeat());
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}
---------------------------------------------------------------------------------------------------
/**
 * 具体建造者
 */
public class OfoBikeBuilder extends Builder{
    @Override
    public void frameBuild() {
        bike.setFrame("铁");
        System.out.println("ofo单车框架是"+bike.getFrame());
    }

    @Override
    public void seatBuild() {
        bike.setSeat("泡沫");
        System.out.println("ofo单车坐垫是"+bike.getSeat());
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}
  • 指挥者:
/**
 * 指挥者
 */

public class Director {
    //声明Builder对象
    private Builder builder;
    //有参构造方法
    public Director(Builder builder){
        this.builder = builder;
    }
    //构造顺序等装饰操作,只是调用而已,真实的创建在实现Builder的实体类中
    public Bike construct(){
        builder.frameBuild();
        builder.seatBuild();
        return builder.createBike();
    }
}
  • 客户端:
public class Client {
    public static void main(String[] args) {
        Director director = new Director(new MobikeBuilder());
        director.construct();
    }
}

【4】个人理解的与抽象工厂模式的区别:

  • 感觉抽象工厂模式,只在乎创建对象,而建造者模式是在指挥者规定的一定顺序下,有序的,有条理的,有步骤的创建这个对象

【5】现在常用的非 指挥者-建造者模式: 链式创造(建造者模式拓展)

经典的「建造者-指挥者」模式现在已经不太常用了,现在建造者模式主要用来通过链式调用生成不同的配置。比如我们要制作一杯珍珠奶茶。它的制作过程是稳定的,除了必须要知道奶茶的种类和规格外,是否加珍珠和是否加冰是可选的。使用建造者模式表示如下:

public class MilkTea {
        private final String type;
        private final String size;
        private final boolean pearl;
        private final boolean ice;
        private MilkTea(Builder builder) {
            this.type = builder.type;
            this.size = builder.size;
            this.pearl = builder.pearl;
            this.ice = builder.ice;
}
        public String getType( ) {
            return type;
    }
        public String getSize() {
            return size;
    }
        public boolean isPear1() {
            return pearl;
    }
        public boolean isIce() {
            return ice;
    }
        public static class Builder {
            private final String type;
            private String size ="中杯";
            private boolean pearl = true;
            private boolean ice = false;
            public Builder(String type) {
                this.type = type;
        }
            public Builder size( String size) {
                this.size = size;
                return this;
        }
            public Builder pear1 ( boolean pearl) {
                this.pearl = pearl;
                return this;
        }
            public Builder ice( boolean cold) {
                this.ice = cold;
                return this;
        }
            public MilkTea build( ) {
                return new MilkTea(this);
        }
}

  • 可以看到,我们将MilkTea的构造方法设置为私有的,所以外部不能通过new构建出MilkTea实例,只能通过Builder构建。对于必须配置的属性,通过Builder的构造方法传入,可选的属性通过Builder的链式调用方法传入,如果不配置,将使用默认配置,也就是中杯、加珍珠、不加冰。根据不同的配置可以制作出不同的奶茶:
public class User {
        private void buyMilkTea() {
        MilkTea milkTea = new MilkTea
                .Builder("原味")
                .build();
        show(milkTea);


        MilkTea chocolate =new MilkTea.Builder("巧克力味")
                .ice(false)
                .build();
        show( chocolate);
        MilkTea strawberry = new MilkTea.Builder("草莓味")
                                        .size("大杯")
                                        .pearl(false)
                                        .ice(true).build();
        show( strawberry);
    }
            private void show(MilkTea milkTea) {
            String pearl;
            if (milkTea.isPear1())
                pearl ="加珍珠";
            else
                pearl = "不加珍珠";
            String ice;
            if (milkTea.isIce()){
                    ice ="加冰";
            }else {
                ice = "不加冰";
            }
            System.out.println("一份"+milkTea.getSize() + "、"+
                pearl + "、"
                + ice + "的"
                + milkTea.getType() +"奶茶");
    }
}

设计模式——建造者模式(使用director指挥者和不适用director结合代码分析)_第5张图片

使用建造者模式的好处是不用担心忘了指定某个配置,保证了构建过程是稳定的。在OkHttp、Retrofit等著名框架的源码中都使用到了建造者模式。

【6】优缺点说明:

优点:

  • 建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。

  • 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦使得相同的创建过程可以创建不同的产品对象。

  • 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得仓建过程更加清晰,也更方便使用程序来控制创建过程。

  • 建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。
    缺点:

  • 造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

  • 参考:如何学习设计模式

你可能感兴趣的:(设计模式,设计模式,java,spring,python,面试)