设计模式之建造者模式

建造者模式

概念

将构建一个复杂对象分成几个部分(多道工序),构建步骤顺序不一致会导致对象表示不同,原来我们直接 A a = new A(); a.setXXX() … A类有很多属性,如果后面需要修改构建步骤顺序时,改动量就很大。

建造模式:当创建复杂对象时,将对象的组成部件和装配这些部件方式(组装部件顺序)分离开,这样灵活的建造对应的对象。对象的构建和对象的表示进行分离。

由于构建的对象很复杂,所以就需要将类划分成几部分,这个几个部分就是下面看到的PhoneBuilder类中的几个方法,然后每个方法会进行set对应的属性值。最后会提供一个方法返回建造完成后的对象。

使用场景

(1)相同的方法,不同的执行顺序,产生不同的事件结果。

(2)多个部件都可以装配到一个对象中,但是产生的运行结果又不相同。

(3)产品类非常复杂,或者产品类中调用顺序不同产生不同的作用,这时候使用建造者模式非常是适合。

(4)当初始化一个复杂的对象,如:好多参数,且很多参数都具有默认值。

和工厂模式区别

通过下面的类图可以发现,和之前讲解的工厂方法模式类似,但是工厂方法模式是通过不同具体工厂获取对象,而建造者模式是通过不同具体构造器建造(初始化)对象,工厂方法模式可以和建造模式结合使用,工厂模式中的对象可以通过建造模式来建造。

类图

设计模式之建造者模式

使用场景(3)的代码实例

Phone 手机的抽象类

/**
 * @author dynamo2120
 * @create 2018-09-28 12:01 PM
 * @description 抽象产品 手机
 **/
public abstract class Phone {
    private String brand;
    private String osPart1;
    private String osPart2;
    private String screen;

    public String getBrand() {
        return brand;
    }

    //设置商标
    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getOsPart1() {
        return osPart1;
    }

    //初始化系统部件1
    public void setOsPart1(String osPart1) {
        this.osPart1 = osPart1;
    }

    public String getOsPart2() {
        return osPart2;
    }

    //初始化系统部件2
    public void setOsPart2(String osPart2) {
        this.osPart2 = osPart2;
    }

    public String getScreen() {
        return screen;
    }

    //初始化屏幕
    public void setScreen(String screen) {
        this.screen = screen;
    }

    //充电方式,由子类实现
    public abstract void charge();

    @Override
    public String toString() {
        return "Phone{" +
                "brand='" + brand + '\'' +
                ", osPart1='" + osPart1 + '\'' +
                ", osPart2='" + osPart2 + '\'' +
                ", screen='" + screen + '\'' +
                '}';
    }
}

ApplePhone 具体的手机


/**
 * @author dynamo2120
 * @create 2018-09-28 12:04 PM
 * @description 苹果手机
 **/
public class ApplePhone extends Phone {

    @Override
    public void charge() {
        System.out.println("普通冲电");
    }
}

SamsungPhone 具体的手机

/**
 * @author dynamo2120
 * @create 2018-09-28 12:05 PM
 * @description 三星手机
 **/
public class SamsungPhone extends Phone {


    @Override
    public void charge() {
        System.out.println("快冲电");
    }
}

PhoneBuilder 抽象手机建造者

/**
 * @author dynamo2120
 * @create 2018-09-28 2:29 PM
 * @description 抽象的手机建造者
 *
 * 将对象的建造和表示分离开
 **/
public interface PhoneBuilder {
    //构造商标
    void buildBrand();
    //构造系统组件
     void buildOs();
    //构造屏幕
    void buildScreen();

    Phone createPhone();
}

ApplePhoneBuilder 具体建造者

/**
 * @author dynamo2120
 * @create 2018-09-28 2:32 PM
 * @description 苹果手机建造类
 **/
public class ApplePhoneBuilder implements PhoneBuilder {

    private ApplePhone applePhone = new ApplePhone();

    @Override
    public void buildBrand() {
        applePhone.setBrand("Aapple");
    }

    @Override
    public void buildOs() {
        applePhone.setOsPart1("ios part1");
        applePhone.setOsPart2("ios part2");

    }

    @Override
    public void buildScreen() {
        applePhone.setScreen("screen1");
    }

    @Override
    public Phone createPhone() {
        return applePhone;
    }
}

SamsungPhoneBuilder 具体建造者

/**
 * @author dynamo2120
 * @create 2018-09-28 2:32 PM
 * @description
 **/
public class SamsungPhoneBuilder implements PhoneBuilder {
    private SamsungPhone samsungPhone = new SamsungPhone();

    @Override
    public void buildBrand() {
        samsungPhone.setBrand("samsung");
    }

    @Override
    public void buildOs() {
        samsungPhone.setOsPart1("android part1");
        samsungPhone.setOsPart2("android part2");
    }

    @Override
    public void buildScreen() {
        samsungPhone.setScreen("screen2");
    }

    @Override
    public Phone createPhone() {
        return samsungPhone;
    }
}

Director 指挥者,如何通过PhoneBuilder提供的方法进行组装这些部件

/**
 * @author dynamo2120
 * @create 2018-09-28 2:53 PM
 * @description 指导对象建造步骤,也就是初始化对象过程顺序
 * <p>
 * 可以任意改变构造对象的顺序,达到不同的效果
 **/
public class Director {
    private PhoneBuilder phoneBuilder;

    public Director(PhoneBuilder phoneBuilder) {
        this.phoneBuilder = phoneBuilder;
    }

    public Phone buildPhone() {
        phoneBuilder.buildBrand();
        phoneBuilder.buildOs();
        phoneBuilder.buildScreen();
        return phoneBuilder.createPhone();
    }
}

Client 测试类

/**
 * @author dynamo2120
 * @create 2018-09-28 2:57 PM
 * @description
 **/
public class Client {

    public static void main(String[] args) {
        PhoneBuilder applePhoneBuilder = new ApplePhoneBuilder();
        Director director1 = new Director(applePhoneBuilder);
        Phone applePhone = director1.buildPhone();
        System.out.println("applePhone" + applePhone);

        PhoneBuilder samSungPhoneBuilder = new SamsungPhoneBuilder();
        Director director2 = new Director(samSungPhoneBuilder);
        Phone samSungPhone = director2.buildPhone();
        System.out.println("samSungPhone" + samSungPhone);
    }
}

运行结果

applePhonePhone{brand='Aapple', osPart1='ios part1', osPart2='ios part2', screen='screen1'}
samSungPhonePhone{brand='samsung', osPart1='android part1', osPart2='android part2', screen='screen2'}

使用场景(4)的代码实例

ConnectionProfile 这里仅仅列举了两个属性,实际上是有很多属性的,而且属性在初始化时都不可必填参数

/**
 * @author dynamo2120
 * @create 2018-07-28 7:16 PM
 * @description
 *
 * 构造对象
 *
 * 1、常用的就是通过重载构造方法,如果类有很多个属性时会发现构造方法也很多,并且有时候只有几个属性是必须的,也会将其他属性一起初始化
 *
 * 2、使用set方法进行设置属性,会使用大量的setXXX方法,在某个时刻对象的状态是不一致的,如果在多线程情况下,另外一个线程在修改某个属性时,会产生对象状态不一致
 *
 * 3、使用建造者模式,在类中定义一个静态内部类Builder,如果是必须传的参数在 构造方法Builder(String name),其他都是可选参数 age(int age) sex(String sex) 这样就更灵活的构建对象
 *
 *
 **/
public class ConnectionProfile {

    private String name;
    private String desciption;

    public ConnectionProfile() {

    }

    public ConnectionProfile(String name, String desciption) {
        this.name = name;
        this.desciption = desciption;
    }

    public static void main(String[] args) {
        ConnectionProfile.Builder builder = new ConnectionProfile.Builder("by builder set name").withDescription("by builder set description");
        ConnectionProfile connectionProfile = builder.build();
        System.out.println("name=" + connectionProfile.getName() + " decription=" + connectionProfile.getDesciption());
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesciption() {
        return desciption;
    }

    public void setDesciption(String desciption) {
        this.desciption = desciption;
    }

    public static class Builder {
        //里面的属性和ConnectionProfile中的属性相同
        private String name;
        private String description;

        //构建ConnectionProfile对象必须传的参数
        public Builder(String name) {
            this.name = name;
        }
        //可选的参数
        public Builder withDescription(String description) {
            this.description = description;
            return this;
        }

        public ConnectionProfile build() {
            return new ConnectionProfile(name, description);
        }
    }
}

运行结果

name=by builder set name
 decription=by builder set description