建造者模式:使用多个简单的对象一步步构建成一个复杂的对象,它提供了一种创建对象的最佳方式。
建造者模式的使用目的:将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
优点:建造者独立,易拓展;便于控制细节风险。
示例场景
在游戏开发中,英雄Hero表示一个人物,他们以不同职业Occupation的形式来展现,比如可以转职成战士或者射手,战士的装备是长剑、重甲,射手的装备是弓、皮甲。
让我们使用建造者模式来创建不同职业的英雄,这个过程中要注意区分和抽象工厂模式的区别。
创建一个英雄和装备接口类:
package com.cc.builder;
/**
* 英雄接口类
* @author cc
* @date 21-12-19 11:48
*/
public interface Hero {
String name();
}
package com.cc.builder;
/**
* 装备接口类
* @author cc
* @date 21-12-19 0:24
*/
public interface Equip {
String name();
}
然后是英雄和装备的实现类:
package com.cc.builder;
/**
* 英雄实现类:战士
* @author cc
* @date 21-12-19 11:57
*/
public class Warrior implements Hero {
@Override
public String name() {
return "Warrior";
}
}
package com.cc.builder;
/**
* 英雄实现类:射手
* @author cc
* @date 21-12-19 11:58
*/
public class Shooter implements Hero {
@Override
public String name() {
return "Shooter";
}
}
package com.cc.builder;
/**
* 装备实现类:长剑
* @author cc
* @date 21-12-19 0:03
*/
public class Sword implements Equip {
@Override
public String name() {
return "Sword";
}
}
package com.cc.builder;
/**
* 装备实现类:弓
* @author cc
* @date 21-12-19 0:04
*/
public class Bow implements Equip {
@Override
public String name() {
return "Bow";
}
}
package com.cc.builder;
/**
* 装备实现类:重甲
* @author cc
* @date 21-12-19 0:29
*/
public class HeavyArmor implements Equip {
@Override
public String name() {
return "Heavy Armor";
}
}
package com.cc.builder;
/**
* 装备实现类:皮甲
* @author cc
* @date 21-12-19 0:28
*/
public class LeatherArmor implements Equip {
@Override
public String name() {
return "Leather Armor";
}
}
接着就是职业实体类,这个类包含了英雄和装备的信息:
package com.cc.builder;
import java.util.ArrayList;
import java.util.List;
/**
* 职业实体类
* @author cc
* @date 21-12-19 12:00
*/
public class Occupation {
private List<Equip> equips = new ArrayList<>();
private Hero hero;
public Occupation(Hero hero) {
this.hero = hero;
}
// 添加装备
public void addEquip(Equip equip) {
equips.add(equip);
}
// 展示信息
public void showInformation() {
System.out.println("Hero:" + hero.name());
for (Equip equip : equips) {
System.out.println(equip.name());
}
}
}
创建职业建造者类:
package com.cc.builder;
/**
* 职业建造者
* @author cc
* @date 21-12-19 12:04
*/
public class OccupationBuilder {
// 建造一个战士职业
public Occupation prepareWarrior() {
Occupation occupation = new Occupation(new Warrior());
occupation.addEquip(new Sword());
occupation.addEquip(new HeavyArmor());
return occupation;
}
// 建造一个射手职业
public Occupation prepareShooter() {
Occupation occupation = new Occupation(new Shooter());
occupation.addEquip(new Bow());
occupation.addEquip(new LeatherArmor());
return occupation;
}
}
测试一下:
package com.cc.builder;
public class Main {
public static void main(String[] args) {
OccupationBuilder occupationBuilder = new OccupationBuilder();
{
Occupation occupation = occupationBuilder.prepareWarrior();
occupation.showInformation();
}
System.out.println("");
{
Occupation occupation = occupationBuilder.prepareShooter();
occupation.showInformation();
}
}
}
结果:
Hero:Warrior
Sword
Heavy Armor
Hero:Shooter
Bow
Leather Armor
建造者模式总结
看回我们上面一开始对建造者模式的介绍
建造者模式使用多个简单的对象一步步构建成一个复杂的对象,它提供了一种创建对象的最佳方式。
建造者模式的使用目的:将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
优点:建造者独立,易拓展;便于控制细节风险。
- 我们的目的是得到一个职业对象,单独一个英雄或者装备都只是这个职业的一部分,借助建造者模式,我们将各个简单对象组合成了一个复杂对象,调用者不需要关心对象的具体创建流程,仅需要知道一个调用函数、对象名或者类型即可
- 在测试模块中可以看到,同样的构建过程,可以创建出战士或者射手的具体表示
- 独立易拓展,当我们有新的需求时,创建一个新的建造者类就可以,基本不用修改原有代码。如在示例中,我们想创建一个法师职业,可以在OccupationBuilder职业建造者类中添加函数,也可以新建一个MasterOccupationBuilder。
建造者模式和抽象工厂的区别
在前面的文章Java设计模式之工厂模式中,我们采用的都是游戏中的战士、射手的示例,在学习建造者模式的过程中,我们很容易混淆它和抽象工厂,其实它们的区别还是比较明显的,仔细看两者的代码可以发现,抽象工厂中,每一个工厂函数就可以创造一个对象,它们生产的是多个产品;而建造者模式,是所有的创建函数加起来才能实现一个对象,对应了开头所描述的:建造者模式使用多个简单的对象一步步构建成一个复杂的对象。
建造者模式和抽象工厂的使用场景
抽象工厂:一系列相关的产品对象组合起来才能工作,比如一个支持加减乘除的计算器,每一个功能函数(加减乘除)都可以单独抽出来使用,但是为了生产计算器产品,通过抽象工厂的方式将它们的产品族组合起来,我们生产一个计算器,就可以拥有加减乘除这所有的功能。
建造者:汽车是一个十分复杂的对象,它是通过车轮、车身、车门、引擎等多个部件组装而成,单独的一个部件没有意义,组装成一个对象才是目的。
所以建造者模式主要用在分步创建一个复杂对象的场景,主要关心构建的过程细节;而抽象工厂则是用于一个系列产品的创建,不需要关心构建过程,只关心是由什么工厂生产。