建造者设计模式
盖房项目需求:
1)需要建房子:过程为打地基,砌墙,封顶;(每种房子的建造过程是相同的)
2)房子有各种各样的,如:普通平房,高楼大厦,别墅,每种房子的建造过程是相同的,但是要求是不同的;
代码案例一:
//由于所有的房子建造的过程都是相同的,所以可以把房子抽象成一个抽象类;
public abstract class AbstractHourse {
private String baise;
private String wall;
private String roofed;
//打地基
public abstract void builderBasic();
//砌墙
public abstract void builderWalls();
//封顶
public abstract void builderRoofed();
//固定的建造顺序
public void builder() {
builderBasic();
builderWalls();
builderRoofed();
}
}
//实现类
public class CommonHouse extends AbstractHourse {
public void builderBasic() {
setBaise("普通房子打地基5m");
System.out.println("普通房子打地基");
}
public void builderWalls() {
setWall("普通房子砌墙10cm");
System.out.println("普通房子砌墙");
}
public void builderRoofed() {
setRoofed("普通房子封顶20cm");
System.out.println("普通房子封顶");
}
}
//测试类
public class Client {
public static void main(String[] args) {
CommonHouse commonHouse = new CommonHouse();
commonHouse.builder();
}
}
优点是结构简单,易理解
缺点是程序的拓展和维护性不好,这种设计方案,把产品和创建产品的过程封装在一起,耦合性增强了。
解决方案:将产品和产品的构建过程解耦 =>建造者模式
什么是建造者设计模式?
建造者设计模式是一个构造复杂对象的设计模式,在一个软件系统中,可能会面临创建一个复杂对象的工作,如果使用单一的方法或者单一的对象来创建会比较烦琐,当所创建复杂对象发生改变时,整个系统就可能面临剧烈的变化。这时就需要我们将这个复杂对象的创建过程分解成若干部分,各个子部分用一定的算法构成。但是,子部分可能会经常发生变化,如何能保证整体创建工作的稳定性呢?这就需要建造者模式,建造者模式把复杂对象的创建与表示分离,使得同样的构建过程可以创建不同的表示。
建造者设计模式的角色
① Product(产品角色):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
② builder(抽象建造者):给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。通常还包含一个返回复杂产品的方法 getResult()。
③ ConcreteBuilder(具体建造者):实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。在建造过程完成后,提供产品的实例。
④ Director(指挥者):调用具体建造者来创建复杂对象的各个部分,在指挥者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。隔离客户和对象的生产过程。
代码案例二:(使用建造者模式解决刚才的盖房问题)
//房子类(产品类)
public class House {
private String baise;
private String wall;
private String roofed;
}
//抽象的建造者
public abstract class HouseBuilder {
protected House house=new House();
//建造的流程
public abstract void buildBasic();
public abstract void buildWalls();
public abstract void buildRoofed();
//建造房子,房子建造好后将房子返回
public House buildHouse() {
return house;
}
}
//实际建造者(建造普通房)
public class CommonHouse extends HouseBuilder {
public void buildBasic() {
house.setBaise("普通房子打地基深度5米");
System.out.println("普通房子打地基深度5米");
}
public void buildWalls() {
house.setWall("普通房子砌墙厚度10厘米");
System.out.println("普通房子砌墙厚度10厘米");
}
public void buildRoofed() {
house.setRoofed("普通房子封顶房顶厚度15厘米");
System.out.println("普通房子封顶房顶厚度15厘米");
}
}
//实际建造者(建造高楼大厦)
public class HighBuilding extends HouseBuilder {
public void buildBasic() {
house.setBaise("高楼大厦打地基深度50米");
System.out.println("高楼大厦打地基深度50米");
}
public void buildWalls() {
house.setWall("高楼大厦砌墙厚度20cm");
System.out.println("高楼大厦砌墙厚度20cm");
}
public void buildRoofed() {
house.setRoofed("高楼大厦封顶,玻璃封顶");
System.out.println("高楼大厦封顶,玻璃封顶");
}
}
//指挥者
//指挥者类,指挥者会指挥建造流程,返回建造好的房子
public class HouseDirector {
HouseBuilder houseBuilder=null;
//通过构造方法传参的方式初始化建造的房子类型
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder=houseBuilder;
}
//建造不同房子是可通过set修改建造的什么房子
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
//如何处理建造房子的流程由指挥者处理
public House constructHouse() {
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.buildRoofed();
return houseBuilder.buildHouse();
}
}
//用户类
public class Client {
public static void main(String[] args) {
//盖普通房子
CommonHouse commonHouse = new CommonHouse();
//创建盖房的指挥者
HouseDirector houseDirector = new HouseDirector(commonHouse);
//完成盖房,放回盖好的房子
House constructHouse = houseDirector.constructHouse();
System.out.println("------------------------");
//盖高楼大厦
HighBuilding highBuilding = new HighBuilding();
houseDirector.setHouseBuilder(highBuilding);
houseDirector.constructHouse();
}
}
代码案例三:
//产品
public class Robot {
private String head;//头
private String hand;//手
private String foot;//脚
private String body;//身体
}
//建造者接口
public interface Builder { //可为抽象类也可以是接口
public abstract void builderHand();
public abstract void builderHead();
public abstract void builderFoot();
public abstract void builderBody();
public abstract Robot createRobot();
}
//接口实现类
public class ATMBuilder implements Builder {
private Robot robot;
public ATMBuilder() {
this.robot = new Robot();
}
@Override
public void builderHand() {
robot.setHand("阿童木的手");
}
@Override
public void builderHead() {
robot.setHead("阿童木的头");
}
@Override
public void builderFoot() {
robot.setFoot("阿童木的脚");
}
@Override
public void builderBody() {
robot.setBody("阿童木的身体");
}
@Override
public Robot createRobot() {
return robot;
}
}
//指挥者
public class Director {
public Robot createRobotDirector(Builder builder) {
builder.builderFoot();
builder.builderBody();
builder.builderHand();
builder.builderHead();
return builder.createRobot();
}
}
//用户
public class User {
public static void main(String[] args) {
Director director = new Director();
ATMBuilder atmBuilder = new ATMBuilder();
Robot createRobotDirector2 = director.createRobotDirector(atmBuilder);
System.out.println(createRobotDirector2);
}
}
实用范围
① 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
②当构造过程必须允许被构造的对象有不同表示时。
③创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
建造者模式适用于对象结构复杂、对象构造和表示分离的情况。任何一种软件设计模式的最终目标都是实现软件的高内聚、低耦合,实现易扩展、易维护。建造者设计模式的实质是解耦组装过程和创建具体部件,使得不用去关心每个部件是如何组装的,只需要知道各个部件是干什么的(实现什么功能)。建造者模式使得产品内部的结构表现可以独立变化,客户端不需要知道产品内部结构的组成细节。
建造者模式的注意事项和细节
1)用户不需要知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
2)每个具体建造者都是相对独立的,而与其他的具体建造者无关,因此可以很方便地替换具体的建造者或者增加新的具体建造者,用户使用不同的具体建造者就可以得到不同的产品对象
3)可以更加精细地控制产品地创建过程,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
4)增加新的具体建造者无需修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合**“开闭原则”**
建造者设计模式的优点和缺点
**优点:**建造者设计模式的优点在于其构建和表示的分离,有效地将复杂对象处理过程分解,降低功能模块之间的耦合度,增强模块内部的内聚度,使得其在软件设计模式中具有极其重要的位置。
缺点: 1)产品的组成部分必须相同,这限制了其使用范围
2)如果产品的内部变化复杂,该模式会增加很多的建造者类。