建造者模式
建造者模式也是创建型的设计模式。建造者模式有许多的变种,举个小eg,比如泡脚牛蛙,不同的店制作的方式可能不一样,这家店偏辣,那家店偏咸等,这时候就需要用到建造者模式。先看看传统的建造者模式。
一、传统的建造者模式
建造者模式的本质:分离对象子组件的单独构造和装配。该模式有2个重要角色
- Diector:导演,装配者。用来导演零件的装配,起到封装作用,防止上层模块进入到构造者内部。
- builder:构造者,用来构造零件,抽象类,确定产品由什么组成。
优点:用户不需要知道内部的实现细节,封装性好。易扩展。
缺点:如果内部复杂,会使得建造类非常多。
java中个StringBuilder和StringBuffer也运用到了建造者模式。
1、建立一个car类,省略代码类引擎、变速箱和底盘的创建
public class Car{
private Engine engine;
private TransmissionBox transmissionBox;
private Chassis chassis;
getter and setter
}
2、建立一个builder抽象类
public abstract class CarBuilder{
public abstract void buildEngine();
public abstract void buildTransmissionBox();
public abstract void buildChassis();
//获取真正结果方法
public abstract Car getcar();
}
3、继承抽象类的builder具体实现类
//Mazda产品
public class MazdaCarBuilder extends CarBuilder{
private Car car = new Car();
public void buildEngine(){
car.setEngine(new MazdaEngine());
}
public void buildTransmissionBox(){
car.setTransmissionBox(new MazdaTransmissionBox());
}
public void buildChassis(){
car.setChassis(new MazdaChassis());
}
public Car getCar(){
return car;
}
}
//BWM产品
public class BWMCarBuilder extends CarBuilder{
private Car car = new Car();
public void buildEngine(){
car.setEngine(new BWMEngine());
}
public void buildTransmissionBox(){
car.setTransmissionBox(new BWMTransmissionBox());
}
public void buildChassis(){
car.setChassis(new BWMChassis());
}
public Car getCar(){
return car;
}
}
4、创建一个Diector类
public class Diector{
public void construct(CarBuilder carbuilder){
carbuilder.buildEngine();
carbuilder.buildTransmissionBox();
carbulider.buildChassis();
}
}
5、测试
public class test{
private static void main(String[] args){
Diector diector = new Diector();
CarBuilder mazdaCarBuilder = new MazdaCarBuilder();
diector.construct(mazdaCarBuilder);
Car car = mazdaCarBuilder.getCar();
}
}
其实乍一看,看上去确实和工厂模式有点相似,但是建造者模式更加关注零件装配的顺序。
接下来再看一个例子
以我们去看点外卖为例,比如KFC,我们可以买汉堡,也可以买饮料,汉堡可以是香辣鸡腿堡,可以是奥尔良鸡腿堡等,这些东西外卖包装一般都是盒子,饮料可以是雪顶(笔者比较喜欢),也可以是莫吉托,一般都是装在纸杯里的。
1、创建food接口和packing接口
public interface Food{
//获取名称
public Sting getName();
//获取包装
public Packing getPacking();
}
public interface Packing{
public String getPacking();
}
2、建立wrapper(纸盒),papercup(纸杯)两个具体packing实现类
public class Wrapper implements Packing{
@Override
public String getPacking(){
return "这是纸盒包装";
}
}
public class Papercup implements Packing{
@Override
public String getPacking(){
return "这是纸杯包装";
}
}
3、创建两个类型产品的抽象类
public abstract class Hamburg implements Food{
//获取包装
@Override
public Packing getPacking(){
return new Wrapper();
}
}
public abstract class Drink implements Food{
//获取包装
@Override
public Packing getPacking(){
return new Papercup();
}
}
4、建立具体食物
public class ZingerBurger extends Hamburg{
@Override
public Packing getName(){
return "香辣鸡腿堡";
}
}
public class OrleansdrumstickCastle extends Hamburg{
@Override
public Packing getName(){
return "奥尔良鸡腿堡";
}
}
public class Snowtopcoffee extends Drink{
@Override
public Packing getName(){
return "雪顶咖啡";
}
}
public class Mojito extends Drink{
@Override
public Packing getName(){
return "莫吉托";
}
}
接下来就是建造者模式使用的关键
对于套餐销售,是商家进行固定搭配,这个搭配买家是不能修改的
5、combo的建立(套餐)
public class Combo{
private List<Food> foods = new ArrayList<>();
public void addFood(Food food){
foods.add(food);
}
public void printCombo(){
for(Food food: foods ){
System.out.print(food.getName() + food.getPacking().getPacking());
}
}
}
6、建立builder类,我们自定香辣配雪顶(A套餐),奥尔良配莫吉托(B套餐)
public class ComboBuilder{
public Combo getA(){
Combo combo = new Combo();
combo.addFood(new ZingerBurger());
combo.addFood(new Snowtopcoffee());
return combo;
}
public Combo getB(){
Combo combo = new Combo();
combo.addFood(new OrleansdrumstickCastle());
combo.addFood(new Mojito());
return combo;
}
}
这里就根据建造者创建了两个套餐,用户只要知道有套餐A和套餐B可以点就行了
6、测试
public class test{
public static void main(String[] args){
ComboBuilder builder = new ComboBuilder();
Combo combo = bulder.getA();
combo.printCombo();
// 同理B套餐
......
}
}
二、目前客户端常用的建造者模式
目前常用建造者模式一半是先new一个builder,然后再链式的调用一堆方法,最后再调用一次build()方法,创建出我们想要的对象。依然以car举个例子:
1、建立一个car类
Class Car{
//一般建造者模式适合用于属性较多,其中有选填必填等属性的类创建
private Engine engin;
private TransmissionBox transmissionBox;
private Chassis chassis;
//私有化构造器,防止客户端直接new
private Car(Engine engin,TransmissionBox transmissionBox,Chassis chassis){
this.engin = engin;
this.transmissionBox = tranmissionBox;
this.chassis = chassis;
}
//添加一个静态的方法来获取builder,这个方法不一定要有
public static CarBuilder builder(){
return new CarBulider();
}
//建立一个静态内部类,其有着和主类一样的属性
public static final class CarBuilder(){
//省略这三个类的编写
private Engine engin;
private TransmissionBox transmissionBox;
private Chassis chassis;
//其实这里可以用set的方法,让set方法返回this,但是这样显着不是很优雅。
public CarBuilder engin(Engine engin){
this.engin = engin;
return this;
}
public CarBuilder transmissionBox(TransmissionBox transmissionBox){
this.transmissionBox = transmissionBox;
return this;
}
public CarBuilder chassis(Chassis chassis){
this.chassis = chassis;
return this;
}
public Car build(Engine engin,TransmissionBox transmissionBox,Chassis chassis){
//这里可以做一些自己需要的逻辑判断
if(engin == null){
throw new RuntimeException("车子没有引擎");
}
......
//返回真正需要得到的类
return new Car(engin,transmissionBox,chassis);
}
}
}
这里其实完全可用龙lombok来优化,直接用@Builder注解
2、测试调用
public class test{
public static void main(String[] args){
Car car = Car.builder.engin(xx)
.transmissionBox(xx)
.chassis(xx)
.build();
}
}
这样创建的方式我想非常的常见如果读过jdk部分的源码。