建造者模式

建造者模式是一种设计模式,用于将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。它包括建造者(Builder)、具体建造者(ConcreteBuilder)和指挥者(Director)三个角色。Builder定义构建对象的步骤,ConcreteBuilder实现这些步骤并创建具体产品,Director使用Builder接口来构建产品,而无需关注具体实现。这种模式提供了更好的封装性和扩展性,但维护成本较高,因为产品变化可能导致所有建造者类的改变。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计者模式之建造者模式

前言

在城市之中林立着各种各样的高楼大厦,这些高楼大厦都是具有建筑建构的大型建筑。而想要建造一栋这样的高楼大厦,需要打地基、搭框架,然后自下而上、循序渐进的一层一层盖起来。通常,这样具有这样复杂结构的物体很难一气呵成的建造出来,需要先建造各式各样的小零件,最终通过将这些小零件组装起来形成最终的复杂结构—产品。

定义

建造者模式:将一个复杂对象的构建与它的表示进行分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。一句话就是,将产品的构建过程产品本身相分离。

UML类图

在这里插入图片描述

  • 在建造者模式中,一共有三类角色,分别为建造者(Builder)具体建造者(ConcreteBuilder)以及指挥者(Director),其作用分别是:
    • 建造者:其通常是一个抽象类或接口,定义了生成复杂实例的方法,具体实现交由子类来实现。如通过Builder类的makeTitle、makeString等方法组合起来可以生成文档这个复杂对象。
    • 具体建造者:该类负责实现建造者类中定义的方法,如TextBuilder类要生成一个纯文本形式的文档,HTMLBuilder要生成一个html格式的文档。此外该角色中还定义了获取最终实例的方法–getResult()
    • 指挥者:该角色使用Builder角色来生成实例,他只调用Builder类中定义的方法,而不关心ConcreteBuilder类中的方法,这也就保证了在建造复杂实例这块的程序具有”可替换性“

示例程序

Builder类

Builder类是一个声明了编写文档方法的抽象类。其中,makeTitle、makeString和makeItems分别是编写标题、字符串和条目的方法,而close是完成编写文档的方法。具体程序如下:

public abstract class Builder {

   /**
    * 编写字符串内容
    * @param str
    */
   public abstract void makeString(String str);

   /**
    * 编写标题
    * @param title
    */
   public abstract void makeTitle(String title);

   /**
    * 编写条目
    * @param items
    */
   public abstract void makeItems(String[] items);

   /**
    * 完成编写编写文档
    */
   public abstract void close();
}

Director类

Director类聚合了Builder类,通过construct方法使用Builder类中的方法来构建文档这个对象。最终传递给Director类的Builder类的实例可以是Builder类的任何子类,他们具体实现了编写文档的细节。

public class Director {

   private Builder builder;

   public Director(Builder builder) {
      this.builder = builder;
   }

   public void construct() {
      builder.makeTitle("构建文档");
      builder.makeString("升国旗");
      builder.makeItems(new String[]{"奏国歌", "演讲"});
      builder.close();
   }
}

TextBuilder类

TextBuilder类是Builder类的子类,具体实现了Builder类中定义的编写文档的方法,还额外提供了获取文档实例的方法。

public class TextBuilder extends Builder{

   private StringBuffer buffer = new StringBuffer();
   @Override
   public void makeString(String str) {
      buffer.append("■ " + str + "\n");
   }

   @Override
   public void makeTitle(String title) {
      buffer.append("=========================\n");
      buffer.append("【 " + title + " 】\n");
      buffer.append("\n");
   }

   @Override
   public void makeItems(String[] items) {
      for (int i = 0; i < items.length; i++) {
         buffer.append("\t" + "." + items[i] + "\n");
      }
      buffer.append("\n");
   }

   @Override
   public void close() {
      buffer.append("=========================\n");
   }
   public String getResult(){
      return buffer.toString();
   }
}

HtmlBuilder类

HtmlBuilder类是Builder类的子类,具体实现了Builder类中定义的编写文档的方法,还额外提供了获取文档实例的方法。

public class HtmlBuilder extends Builder{
   private String filename;
   private PrintWriter writer;

   public HtmlBuilder(String filename) {
      this.filename = filename;
   }

   @Override
   public void makeString(String str) {
      writer.println("<p>"+str+"</p>");
   }

   @Override
   public void makeTitle(String title) {
      filename = "e:\\" + filename +".html";
      try {
         writer = new PrintWriter(new FileWriter(filename));
      } catch (IOException e) {
         e.printStackTrace();
      }
      writer.println("<html><head><title>"+title+"</title></head><body>");
      writer.println("<h1>"+title+"</h1>");
   }

   @Override
   public void makeItems(String[] items) {
      writer.println("<ul>");
      for (int i = 0; i < items.length; i++) {
         writer.println("<li>"+items[i]+"</li>");
      }
      writer.println("<ul>");
   }

   @Override
   public void close() {
      writer.println("</body></html>");
      writer.close();
   }

   public String getResult(){
      return filename;
   }
}

Main类

Main类是一个测试类,将Builder类的子类的实例对象传递到Director类的构造器中,而Director类是通过Builder类中提供的方法来构建实例,并不关心具体实现到底是哪个子类,这也就将产品的构建过程(Director)与产品本身(ConcreteBuilder)给隔离开来。

public class Main {
   public static void main(String[] args) {
      TextBuilder builder = new TextBuilder();
      Director director = new Director(builder);
      director.construct();
      System.out.println(builder.getResult());

      HtmlBuilder htmlBuilder = new HtmlBuilder("建造者模式");
      director = new Director(htmlBuilder);
      director.construct();
      System.out.println("文件名为:" +htmlBuilder.getResult());
   }
}

运行结果

TextBuilder

在这里插入图片描述

HtmlBuilder

在这里插入图片描述

在这里插入图片描述

优缺点

  • 优点:
    • 封装性好:产品的构建与表示是分离的。客户端不需要知道产品内部的组成细节,建造者可以对产品的创建过程细化,而不会对其他模块产生影响。
    • 扩展性好:各个具体建造者是相互独立的,有利于系统的解耦。
  • 缺点:维护成本高。每个建造者类只能服务与一种生产模式,如果产品本身(Builder)发生改变,那么所有的具体建造者类都要发生改变,后期维护成本还是很高的。

总结

可以发现,建造者模跟工厂模式是很类似的,都是用来创建对象。但建造者模式注重组装,而工厂模式注重创建。这两者可以结合起来使用,使用工厂模式创建零部件,使用建造者模式组装最后的产品。

建造者模式对产品的构建与表示进行了隔离,相同的构建过程可以生产不同的表示。建造者模式引入了一个非常重要的角色–指挥者(Director),他有两个主要作用:一是将客户端与产品的生产过程进行了隔离;二是控制了产品的生产过程。指挥者面向的是抽象编程,客户端只需要知道具体建造者的类型,就可以通过Director类调用相关建造方法,返回一个产品对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值