0
点赞
收藏
分享

微信扫一扫

设计模式(四)建造者模式

1、概述

生成器模式是一种创建型设计模式, 使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。

2、适用场景

1)避免重叠构造函数,例如:一个类有很多的属性,这时候的构造方法需要传递很多的参数,为了避免这样,会重新写一个相对参数较少的构造方法,但是仍然需要对其他参数进行赋默认值。
2)当需要创建不同的产品类型,此处指比较接近的产品类型,则可以在顶层builder中包含大部分产品属性的赋值方法。

3、实例

有以下场景,我们分别使用常规方式和建造者模式实现:

当前有一个汽车工厂,可以生产的汽车类型有city,sport。
除了汽车之外,同样可以生产汽车的相关手册manual。

汽车有以下的属性:
1、type 类型
2、seats 座位数
3、engine 引擎
4、GPS 导航

分别实现汽车和手册的生产过程

3.1 不适用建造者模式

分别创建车car和手册manual,以及其内部的属性,当前例子中车和手册是相同的属性。

import lombok.Data;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@Data
public class Car {

    private CarType type;

    private int seats;

    private Engine engine;

    private GPS GPS;

    public Car(CarType type, int seats, Engine engine, com.cloud.bssp.designpatterns.builder.withouttdesign.entity.GPS GPS) {
        this.type = type;
        this.seats = seats;
        this.engine = engine;
        this.GPS = GPS;
    }

    public void detail() {
        System.out.println("this is " + type + " car");
        System.out.println("the seats is :" + seats);
        System.out.println("the engine is :" + engine);
        System.out.println("this GPS is :" + GPS);
    }
}
import lombok.Data;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@Data
public class Manual {

    private CarType type;

    private int seats;

    private Engine engine;

    private GPS GPS;

    public Manual(CarType type, int seats, Engine engine, com.cloud.bssp.designpatterns.builder.withouttdesign.entity.GPS GPS) {
        this.type = type;
        this.seats = seats;
        this.engine = engine;
        this.GPS = GPS;
    }

    public void detail() {
        System.out.println("this is " + type + " car");
        System.out.println("the seats is :" + seats);
        System.out.println("the engine is :" + engine);
        System.out.println("this GPS is :" + GPS);
    }
}
/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
public enum CarType {

    SPORT,CITY;
}
import lombok.Data;

/**
 * 汽车引擎
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@Data
public class Engine {

    /**
     * 排量
     */
    private final double volume;
    /**
     * 里程
     */
    private double mileage;

    public Engine(double volume, double mileage) {
        this.volume = volume;
        this.mileage = mileage;
    }
}
import lombok.Data;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */

@Data
public class GPS {

    /**
     * 路线
     */
    private String route;

    public GPS(String route) {
        this.route = route;
    }
}

测试类:

import com.cloud.bssp.BsspUserApplication;
import com.cloud.bssp.designpatterns.builder.withouttdesign.entity.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 客户端
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BsspUserApplication.class)
public class TestDemo {

    @Test
    public void test() {
        //生产运动汽车
        Car sportCar = new Car(
                CarType.SPORT,
                2,
                new Engine(3.0, 0),
                new GPS("haerbin nangang haerbindajie")
        );
        sportCar.detail();
        System.out.println("----------------------------------------");
        //生产城市汽车
        Car cityCar = new Car(
                CarType.CITY,
                4,
                new Engine(2.0, 0),
                new GPS("haerbin nangang haerbindajie")
        );
        cityCar.detail();
        System.out.println("----------------------------------------");
        //生产汽车手册
        Manual manual = new Manual(
                CarType.CITY,
                4,
                new Engine(2.0, 0),
                new GPS("haerbin nangang haerbindajie")
        );
        manual.detail();
        System.out.println("----------------------------------------");
    }

}

结果:

this is SPORT car
the seats is :2
the engine is :Engine(volume=3.0, mileage=0.0)
this GPS is :GPS(route=haerbin nangang haerbindajie)
----------------------------------------
this is CITY car
the seats is :4
the engine is :Engine(volume=2.0, mileage=0.0)
this GPS is :GPS(route=haerbin nangang haerbindajie)
----------------------------------------
this is CITY car
the seats is :4
the engine is :Engine(volume=2.0, mileage=0.0)
this GPS is :GPS(route=haerbin nangang haerbindajie)
----------------------------------------

3.2 建造者实现

使用建造者模式后,代码要比上面的方法多了不少:

创建顶层Builder

import com.cloud.bssp.designpatterns.builder.usedesign.entity.CarType;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.Engine;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.GPS;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
public interface Builder {

    void setCarType(CarType carType);

    void setSeats(int seats);

    void setEngine(Engine engine);

    void setGPS(GPS gps);
}

创建实体类,与3.1中是相同的,这里不重复粘贴了。

创建car的builder:

import com.cloud.bssp.designpatterns.builder.usedesign.entity.Car;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.CarType;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.Engine;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.GPS;
import lombok.Data;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@Data
public class CarBuilder implements Builder {

    private CarType carType;

    private int seats;

    private Engine engine;

    private GPS GPS;

    public Car getResult() {
        return new Car(carType, seats, engine, GPS);
    }
}

创建手册builder:

import com.cloud.bssp.designpatterns.builder.usedesign.entity.*;
import lombok.Data;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@Data
public class ManualBuilder implements Builder {

    private CarType carType;

    private int seats;

    private Engine engine;

    private GPS GPS;

    public Manual getResult() {
        return new Manual(carType, seats, engine, GPS);
    }
}

创建一个builder管理器:

import com.cloud.bssp.designpatterns.builder.usedesign.builder.Builder;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.CarType;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.Engine;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.GPS;

/**
 * TODO
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
public class Director {

    public void constructSportsCar(Builder builder) {
        builder.setCarType(CarType.SPORT);
        builder.setSeats(2);
        builder.setEngine(new Engine(3.0, 0));
        builder.setGPS(new GPS("haerbin nangang haerbindajie"));
    }

    public void constructCityCar(Builder builder) {
        builder.setCarType(CarType.CITY);
        builder.setSeats(4);
        builder.setEngine(new Engine(2.0, 0));
        builder.setGPS(new GPS("haerbin nangang haerbindajie"));
    }
}

测试类:

import com.cloud.bssp.BsspUserApplication;
import com.cloud.bssp.designpatterns.builder.usedesign.builder.CarBuilder;
import com.cloud.bssp.designpatterns.builder.usedesign.builder.ManualBuilder;
import com.cloud.bssp.designpatterns.builder.usedesign.director.Director;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.Car;
import com.cloud.bssp.designpatterns.builder.usedesign.entity.Manual;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 客户端
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BsspUserApplication.class)
public class TestDemo {

    @Test
    public void test() {
        Director director = new Director();
        //生产运动汽车
        CarBuilder carBuilder = new CarBuilder();
        director.constructSportsCar(carBuilder);
        Car sportCar = carBuilder.getResult();
        sportCar.detail();
        System.out.println("-----------------------------------");

        //生产城市汽车
        director.constructCityCar(carBuilder);
        Car cityCar = carBuilder.getResult();
        cityCar.detail();
        System.out.println("-----------------------------------");

        //生产汽车手册
        ManualBuilder manualBuilder = new ManualBuilder();
        director.constructCityCar(manualBuilder);
        Manual manual = manualBuilder.getResult();
        manual.detail();
        System.out.println("-----------------------------------");
    }
}

结果:

this is SPORT car
the seats is :2
the engine is :Engine(volume=3.0, mileage=0.0)
this GPS is :GPS(route=haerbin nangang haerbindajie)
-----------------------------------
this is CITY car
the seats is :4
the engine is :Engine(volume=2.0, mileage=0.0)
this GPS is :GPS(route=haerbin nangang haerbindajie)
-----------------------------------
this Manual CITY car
the Manual seats is :4
the Manual engine is :Engine(volume=2.0, mileage=0.0)
this GManual PS is :GPS(route=haerbin nangang haerbindajie)
-----------------------------------

4、分析

建造者模式基本有以下几个角色:

如上面两种方式的结果显示,都可以实现生产汽车和手册。

结果没什么差异

在没使用建造者的方式中:生产汽车的参数是由客户端自己指定的,并且需要传很多的参数,实际工作中可能需要更多的参数,可能有部分参数是不需要的。

使用建造者模式,用户不需要去具体指定多个参数了,对于客户端更友好

builder:将产品new()提出到builder中,提供产品所拥有的属性设置方法,一类产品都可以使用这个builder进行产品创建。

director:作为builder的管理者,主要控制产品的属性设置,在这个类中,具体指定除了可以生产的产品的构造,并且对属性进行赋值,最终返回一个用户需要的builder。

客户端调用只需要创建需要的产品类型builder,通过管理者director对builder进行属性设置,最终客户端通过调用builder的方法获取最终需要的产品。

极大程度减少并优化的客户端的代码,同时由管理者director限制了产品的种类。

从扩展层层面看
未使用建造者:增加对应的产品类,客户端直接new。
建造者模式:增加builder,并且在director增加可创建的产品的builder构造。

5、总结

优点:
1)遵守单一原则。
2)不同产品,可复用相同的产品创建流程。
3)简化客户端调用方式。去除多参构造的方式。
4)分步骤创建对象。
缺点:
增加多个类,代码复杂度增加。

举报

相关推荐

0 条评论