目录
- 生成器模式
- 生成器模式结构
- 生成器模式应用场景
- 生成器模式优缺点
- 练手题目
- 题目描述
- 输入描述
- 输出描述
- 提示信息
- 题解
生成器模式
生成器模式,又称建造者模式,是一种创建型设计模式, 使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。
生成器模式结构
- 生成器(Builder)接口声明在所有类型生成器中通用的产品构造步骤。
- 具体生成器(Concrete Builders) 提供构造过程的不同实现。具体生成器也可以构造不遵循通用接口的产品。
- 产品(Products)是最终生成的对象。由不同生成器构造的产品无需属于同一类层次结构或接口。
- 主管(Director) 类定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置。
- 客户端(Client) 必须将某个生成器对象与主管类关联。一般情况下,你只需通过主管类构造函数的参数进行一次性关联即可。 此后主管类就能使用生成器对象完成后续所有的构造任务。但在客户端将生成器对象传递给主管类制造方法时还有另一种方式。在这种情况下,你在使用主管类生产产品时每次都可以使用不同的生成器。
通用代码结构示例
//产品类
public class Product1{
...
}
public class Product2{
...
}
//抽象生成器类
public abstract interface Builder{
public void reset();
//生成产品步骤
public void buildStepA();
public void buildStepB();
public void buildStepC();
}
//具体生成器类
public class ConcreteBuilder1 implements Builder{
private Product1 product1 ;
// reset(重置)方法可清除正在生成的对象。
public void reset(){
this.product1=new Product1();
}
//生成产品步骤
public void buildStepA(){
...
};
public void buildStepB(){
...
};
public void buildStepC(){
...
};
//组建产品
public Product1 buildProduct1(){
return this.product1;
}
}
public class ConcreteBuilder2 implements Builder{
private Product2 product2 ;
// reset(重置)方法可清除正在生成的对象。
public void reset(){
this.product2=new Product2();
}
//生成产品步骤
public void buildStepA(){
...
};
public void buildStepB(){
...
};
public void buildStepC(){
...
};
//组建产品
public Product2 buildProduct2(){
return this.product2;
}
}
//导演类 责按照特定顺序执行生成步骤。其在根据特定步骤或配置来生成产品时会很有帮助。
//由于客户端可以直接控制生成器,所以严格意义上来说,该类并不是必需的。
public class Director{
private Builder builder = new ConcreteBulider();
public void getProduct(){
builder.reset();
...
}
}
//客户端
public class Client{
Director director = new Director();
ConcreteBuilder1 bulider1 = new ConcreteBuilder1();
director.getProduct(bulider1);
Product1 product1 = bulider1.buildProduct1();
}
生成器模式应用场景
-
使用生成器模式可避免 “重叠构造函数 (telescoping constructor)” 的出现。
假设你的构造函数中有十个可选参数, 那么调用该函数会非常不方便; 因此, 你需要重载这个构造函数, 新建几个只有较少参数的简化版。 但这些构造函数仍需调用主构造函数, 传递一些默认数值来替代省略掉的参数。
生成器模式让你可以分步骤生成对象, 而且允许你仅使用必须的步骤。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了。
-
当你希望使用代码创建不同形式的产品 (例如石头或木头房屋) 时, 可使用生成器模式。
如果你需要创建的各种形式的产品, 它们的制造过程相似且仅有细节上的差异, 此时可使用生成器模式。基本生成器接口中定义了所有可能的制造步骤, 具体生成器将实现这些步骤来制造特定形式的产品。 同时, 主管类将负责管理制造步骤的顺序。
-
使用生成器构造组合树或其他复杂对象。
生成器模式让你能分步骤构造产品。 你可以延迟执行某些步骤而不会影响最终产品。 你甚至可以递归调用这些步骤, 这在创建对象树时非常方便。生成器在执行制造步骤时, 不能对外发布未完成的产品。 这可以避免客户端代码获取到不完整结果对象的情况。
识别方法:生成器模式可以通过类来识别, 它拥有一个构建方法和多个配置结果对象的方法。 生成器方法通常支持方法链 (例如
someBuilder.setValueA(1).setValueB(2).create()
)。
生成器模式优缺点
优点:
- 你可以分步创建对象, 暂缓创建步骤或递归运行创建步骤。
- 生成不同形式的产品时, 你可以复用相同的制造代码。
- 单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来。
缺点:
- 由于该模式需要新增多个类, 因此代码整体复杂程度会有所增加。
练手题目
题目描述
小明家新开了一家自行车工厂,用于使用自行车配件(车架 frame 和车轮 tires )进行组装定制不同的自行车,包括山地车和公路车。
山地车使用的是Aluminum Frame(铝制车架)和 Knobby Tires(可抓地轮胎),公路车使用的是 Carbon Frame (碳车架)和 Slim Tries。
现在它收到了一笔订单,要求定制一批自行车,请你使用【建造者模式】告诉小明这笔订单需要使用那些自行车配置吧。
输入描述
输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示订单的数量。
接下来的 N 行,每行输入一个字符串,字符串表示客户的自行车需求。
字符串可以包含关键词 “mountain” 或 “road”,表示客户需要山地自行车或公路自行车。
输出描述
对于每笔订单,输出该订单定制的自行车配置。
提示信息
在本例中:产品为自行车,可以有两个建造者:山地车建造者和公路车建造者。
题解
使用模版方法模式和建造者模式实现自行车工厂。
import java.util.ArrayList;
import java.util.Scanner;
//抽象类,模版方法模式创建
abstract class Bicycle{
private ArrayList<String> fittingsList = new ArrayList<String>();
//选用不同配件的方法
protected void useAluminumFrame(){};
protected void useKnobbyTires(){};
protected void useCarbonFrame(){};
protected void useSlimTires(){};
//设置配件列表
public final void setFittingsList(ArrayList<String> list){
this.fittingsList = list;
}
//选用配件,构建自行车
public final void maker(){
for (String fitting : fittingsList) {
switch (fitting) {
case "useAluminumFrame":
useAluminumFrame();
break;
case "useKnobbyTires":
useKnobbyTires();
break;
case "useCarbonFrame":
useCarbonFrame();
break;
case "useSlimTires":
useSlimTires();
break;
default:
System.out.println("不清楚的配件:" + fitting + "请重新输入!");
}
}
}
}
//山地自行车类,并重写父类方法
class MountainBicycle extends Bicycle{
@Override
protected void useAluminumFrame(){
System.out.print("Aluminum Frame ");
}
@Override
protected void useKnobbyTires(){
System.out.println("Knobby Tires ");
}
}
//公路自行车类,并重写父类方法
class RoadBicycle extends Bicycle{
@Override
protected void useCarbonFrame(){
System.out.print("Carbon Frame ");
}
@Override
protected void useSlimTires(){
System.out.println("Slim Tires ");
}
}
//定义建造者接口
interface Builder{
void setFittingList(ArrayList<String> list);
Bicycle getBicycle();
}
//山地自行车建造类
class MountainBicycleBuilder implements Builder{
private MountainBicycle mountainBicycle = new MountainBicycle();
public void setFittingList(ArrayList<String> list){
this.mountainBicycle.setFittingsList(list);
}
public Bicycle getBicycle(){
return this.mountainBicycle;
}
}
//公路自行车建造者类
class RoadBicycleBuilder implements Builder{
private RoadBicycle roadBicycle = new RoadBicycle();
public void setFittingList(ArrayList<String> list){
this.roadBicycle.setFittingsList(list);
}
public Bicycle getBicycle(){
return this.roadBicycle;
}
}
//导演类
class Director{
private ArrayList<String> arrayList = new ArrayList<String>();
private MountainBicycleBuilder mountainBicycleBuilder = new MountainBicycleBuilder();
private RoadBicycleBuilder roadBicycleBuilder = new RoadBicycleBuilder();
public MountainBicycle getMountainBicycle(){
//清理场景
this.arrayList.clear();
//选用配件
this.arrayList.add("useAluminumFrame");
this.arrayList.add("useKnobbyTires");
this.mountainBicycleBuilder.setFittingList(this.arrayList);
return (MountainBicycle)this.mountainBicycleBuilder.getBicycle();
}
public RoadBicycle getRoadBicycle(){
//清理场景
this.arrayList.clear();
//选用配件
this.arrayList.add("useCarbonFrame");
this.arrayList.add("useSlimTires");
this.roadBicycleBuilder.setFittingList(this.arrayList);
return (RoadBicycle)this.roadBicycleBuilder.getBicycle();
}
}
//主程序类
public class Main{
public static void main (String[] args) {
Scanner scanner = new Scanner(System.in);
try {
int num = scanner.nextInt();
scanner.nextLine();
Director director = new Director();
for (int i = 0; i < num; i++) {
String type = scanner.nextLine().toLowerCase().trim();
Bicycle bicycle;
if ("mountain".equals(type)) {
bicycle = director.getMountainBicycle();
} else if ("road".equals(type)) {
bicycle = director.getRoadBicycle();
} else {
System.out.println("无效输入. 请输入 'mountain' 或 'road'.");
continue;
}
bicycle.maker();
}
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
} finally {
scanner.close();
}
}
}