Java设计模式之建造者模式

2,012 阅读5分钟

建造者模式:使用多个简单的对象一步步构建成一个复杂的对象,它提供了一种创建对象的最佳方式。

建造者模式的使用目的:将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

优点:建造者独立,易拓展;便于控制细节风险。

示例场景

在游戏开发中,英雄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设计模式之工厂模式中,我们采用的都是游戏中的战士、射手的示例,在学习建造者模式的过程中,我们很容易混淆它和抽象工厂,其实它们的区别还是比较明显的,仔细看两者的代码可以发现,抽象工厂中,每一个工厂函数就可以创造一个对象,它们生产的是多个产品;而建造者模式,是所有的创建函数加起来才能实现一个对象,对应了开头所描述的:建造者模式使用多个简单的对象一步步构建成一个复杂的对象。

建造者模式和抽象工厂的使用场景

抽象工厂:一系列相关的产品对象组合起来才能工作,比如一个支持加减乘除的计算器,每一个功能函数(加减乘除)都可以单独抽出来使用,但是为了生产计算器产品,通过抽象工厂的方式将它们的产品族组合起来,我们生产一个计算器,就可以拥有加减乘除这所有的功能。

建造者:汽车是一个十分复杂的对象,它是通过车轮、车身、车门、引擎等多个部件组装而成,单独的一个部件没有意义,组装成一个对象才是目的。

所以建造者模式主要用在分步创建一个复杂对象的场景,主要关心构建的过程细节;而抽象工厂则是用于一个系列产品的创建,不需要关心构建过程,只关心是由什么工厂生产。