Java设计模式之创建型模式(四):建造者(生成器)模式

导读:本篇文章讲解 Java设计模式之创建型模式(四):建造者(生成器)模式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、基本介绍

建造者模式(Build Pattern)又称生成器模式,该模式封装一个产品的构造过程,一步一步地创建出一个复杂的对象,它允许用户通过指定复杂对象的类型和具体内容来构建对象,不需要知道内部的构建细节。

下面是建造者的原理UML类图:在这里插入图片描述
建造者模式的四个角色说明:

  1. Product(产品对象):一个具体的产品对象
  2. Builder(抽象建造者):用于创建一个产品对象的各个部件指定的接口/抽象类
  3. ConcreteBuilder(具体建造者):实现接口,构建和装配产品的各个部件。
  4. Director(指挥者):用于创建一个复杂的对象,它主要有两个作用:隔离客户与对象的生产过程和负责控制产品对象的生产过程。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。

二、使用

下面应用建造者模式来解决一个实际案例

1.场景

假设你在广州做一个导游,现在你需要为游客制定多个“羊城一日游”的行程安排的计划,其中每个计划去的景点可能不太一样,另外如果是外地的游客则需要提供旅馆住宿。
所以需要一个弹性的数据结构,代表客人的规划以及所有的变化。要创建这样的计划,就需要使用建造者模式来实现创建复杂的结构的同时,又不会和创建它的步骤混在一起。

2.UML类图设计

在这里插入图片描述
其中PlanA不包含住宿,PlanB包含住宿

3.代码实现

Plan类,担当产品对象的角色

public class Plan {
	public String morningPlan;
	public String afternoonPlan;
	public String nightPlan;
	public String sleepPlan;
//省略getter和setter方法
//省略toString方法

Director类,担当指挥者的角色

public class Director {
	AbstractBuilder planBuilder;

	public Director(AbstractBuilder planBuilder) {
		// TODO Auto-generated constructor stub
		this.planBuilder = planBuilder;
	}

	public void setPlanBuilder(AbstractBuilder planBuilder) {
		this.planBuilder = planBuilder;
	}

	public Plan constructPlan() {
		System.out.println("计划制定:");
		planBuilder.arrangeMorning();
		planBuilder.arrangeAfternoon();
		planBuilder.arrangeNight();
		planBuilder.arrangeSleep();
		return planBuilder.getPlan();
	}
}

AbstractPlanBuilder类,担当抽象建造者的角色

public abstract class AbstractBuilder {
	Plan plan = new Plan();

	public abstract void arrangeMorning();

	public abstract void arrangeAfternoon();

	public abstract void arrangeNight();

	public abstract void arrangeSleep();

	public Plan getPlan() {
		return plan;
	}
}

PlanABuilder,PlanBBuilder都担当具体建造者的角色

public class PlanABuilder extends AbstractBuilder {

	@Override
	public void arrangeMorning() {
		// TODO Auto-generated method stub
		plan.setMorningPlan("出发时间:8:00,目的地:白云山");
		System.out.println("已制定好早上的计划");
	}

	@Override
	public void arrangeAfternoon() {
		// TODO Auto-generated method stub
		plan.setAfternoonPlan("出发时间:12:00,目的地:长隆欢乐世界");
		System.out.println("已制定好下午的计划");
	}

	@Override
	public void arrangeNight() {
		// TODO Auto-generated method stub
		plan.setNightPlan("出发时间: 20:00 ,目的地:广州塔");
		System.out.println("已制定好晚上的计划");
	}
	@Override
	public void arrangeSleep() {
		System.out.println("该计划不安排住宿");
	}
}

public class PlanBBuilder extends AbstractBuilder {

	@Override
	public void arrangeMorning() {
		// TODO Auto-generated method stub
		plan.setMorningPlan("出发时间:8:15,目的地:大夫山");
		System.out.println("已制定好早上的计划");
	}

	@Override
	public void arrangeAfternoon() {
		// TODO Auto-generated method stub
		plan.setAfternoonPlan("出发时间:11:30,目的地:长隆欢乐世界");
		System.out.println("已制定好下午的计划");
	}

	@Override
	public void arrangeNight() {
		// TODO Auto-generated method stub
		plan.setNightPlan("出发时间: 20:00 ,目的地:广州塔");
		System.out.println("已制定好晚上的计划");
	}

	@Override
	public void arrangeSleep() {
		System.out.println("晚上住宿在白天鹅宾馆");
	}

}

Client类作为客户类,只需调用Director的consructPlan即可完成计划对象的创建

public class Client {
	public static void main(String[] args) {
		Director director = new Director(new PlanABuilder());
		Plan p1 = director.constructPlan();
		System.out.println("计划详情:" + p1);
		director.setPlanBuilder(new PlanBBuilder());
		Plan p2 = director.constructPlan();
		System.out.println("计划详情:" + p2);
	}
}

程序运行结果:
在这里插入图片描述

三、典型应用

java.lang.StringBuilder中的建造者模式
StringBuilder类的继承和实现关系,如图:
在这里插入图片描述
Appendable接口定义了三个append方法,其担当抽象建造者的角色,定义了抽象方法。

public interface Appendable {

    Appendable append(CharSequence csq) throws IOException;
    
    Appendable append(CharSequence csq, int start, int end) throws IOException;
    
    Appendable append(char c) throws IOException;
}

AbstractStringBuilder实现了Appendable接口的三个方法,AbstractStringBuilder类担当了具体建造者的角色,当由于其是抽象类,所以不能实例化。

abstract class AbstractStringBuilder implements Appendable, CharSequence {
//省略
    @Override
    public AbstractStringBuilder append(CharSequence s) {
        if (s == null)
            return appendNull();
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof AbstractStringBuilder)
            return this.append((AbstractStringBuilder)s);

        return this.append(s, 0, s.length());
    }
      @Override
    public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                "start " + start + ", end " + end + ", s.length() "
                + s.length());
        int len = end - start;
        ensureCapacityInternal(count + len);
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
    }

    @Override
    public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }
    //省略
  } 

StringBuilder即担当了指挥者角色,同时担当了具体的建造者的角色,还是产品对象。其建造方法是由其父类AbstractStringBuilder来实现,下面三个重载的append方法都是建造方法,只不过比较简单,只有一个方法调用。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
//省略
  @Override
    public StringBuilder append(CharSequence s) {
        super.append(s);
        return this;
    }
    @Override
    public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }
    
    @Override
    public StringBuilder append(char c) {
        super.append(c);
        return this;
    }
   }
   //省略

四、总结

  • 建造者模式的优点:
  1. 在建造者模式中,向客户端隐藏产品内部的表现,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
  2. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。
  3. 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  4. 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
  • 建造者模式的缺点:
  1. 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  2. 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
  • 建造者模式与抽象工厂模式的比较:

与抽象工厂模式相比, 建造者模式返回一个组装好的完整产品 ,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。
在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象

如果将抽象工厂模式看成 汽车配件生产工厂 ,生产一个产品族的产品,那么建造者模式就是一个 汽车组装工厂 ,通过对部件的组装可以返回一辆完整的汽车。

参考:
1.4.建造者模式
2.设计模式 | 建造者模式及典型应用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/44325.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!