GOF23-建造者模式

建造者模式

建造者模式也是创建型的设计模式。建造者模式有许多的变种,举个小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部分的源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值