【设计模式】Builder模式

定义

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

将复杂对象的创建过程与该对象的表示分离开来,以便让同一个创建过程可以创建出不同的表示。

类图



角色

  1. Builder:
    定义一个抽象接口,用于创建Product组成部分
  2. ConcreteBuilder:
    构建并组装Product组成部分;
    定义并跟踪所创建的表示(Product?);
    提供接口,用于查询product。
  3. Director:
    使用Builder接口构建对象
  4. Product:
    表示所创建的复杂对象;——ConcreteBuilder构建product的内部表示并定义它的组装过程;
    包含定义组成部分的类。

示例代码

  • Product

public class MyFile {
   private FileHead fhead;
   private FileContent fcontent;
   private FileEnd fend;
   
   public FileContent getFcontent() {
     return fcontent;
  }
   public void setFcontent(FileContent fcontent) {
     this.fcontent = fcontent;
  }
   public FileEnd getFend() {
     return fend;
  }
   public void setFend(FileEnd fend) {
     this.fend = fend;
  }
   public FileHead getFhead() {
     return fhead;
  }
   public void setFhead(FileHead fhead) {
     this.fhead = fhead;
  }
   public void write(String path) throws IOException{
    File f = new File(path);
    FileWriter fw = new FileWriter(f);
    PrintWriter out = new PrintWriter(fw);
    out.println(fhead.getValue());
    out.println(fcontent.getValue());
    out.println(fend.getValue());
    out.close();   
  }
}
 
Product Part
 
public class FileHead {
   private String value;
   public String getValue() {
     return value;
  }
   public void setValue(String value) {
     this.value = value;
  }
}
 
public class FileContent{
   private String value;
  ...
}
 
public class FileEnd {
   private String value;
  ...
}
  • Builder

public interface FileBuilder {
   void buildHead();
   void buildContent();
   void buildEnd();
  MyFile getResult();
}
  • ConcreteBuilder

public class TxtBuilder implements FileBuilder{
   private FileHead fh = new FileHead();
   private FileContent fc = new FileContent();;
   private FileEnd fe = new FileEnd();
   public void buildHead() {
    fh.setValue( "This is text file");
  }
   public void buildContent() {
    fc.setValue( "this is my content");
  }
   public void buildEnd() {
    fe.setValue( "this is the end of the file");
  }
   public MyFile getResult() {
    MyFile my = new MyFile();
    my.setFcontent(fc);
    my.setFhead(fh);
    my.setFend(fe);
     return my;
  }
}
 
 
public class XmlBuilder implements FileBuilder {
       private FileHead fh = new FileHead();
       private FileContent fc = new FileContent();
       private FileEnd fe = new FileEnd();
     
   public void buildHead() {
    fh.setValue( "<?xml version=\"1.0\" encoding=\"GB2312\"?><content>"); 
  }
   public void buildContent() {
    fc.setValue( "<test>asdasd</test>");
  }
   public void buildEnd() {
    fe.setValue( "</content>");   
  }
  //组装product
   public MyFile getResult() {
    MyFile my = new MyFile();
    my.setFcontent(fc);
    my.setFhead(fh);
    my.setFend(fe);
     return my;
  }
}
  • Director


public class FileDirector {
       private FileBuilder filebuilder;
       public FileDirector(FileBuilder filebuilder){
         this.filebuilder =filebuilder;
      }
 
      //一步一步创建product
       public void construct(){
        filebuilder.buildHead();
        filebuilder.buildContent();
        filebuilder.buildEnd();
      }
}
  • Client

public class Demo {
   public static void main(String[] args) throws IOException {
               //TxtBuilder
               FileBuilder fb = new TxtBuilder();
               FileDirector fd = new FileDirector(fb);             
               fd.construct();
              MyFile my = fb.getResult();
              my.write( "D:/test.txt");
             
               //XmlBuilder --改变builder,就改变了product的内部表示
              FileBuilder fbxml = new XmlBuilder();
              FileDirector fdxml = new FileDirector(fbxml);
              fdxml.construct();
              MyFile myxml =fbxml.getResult();
              myxml.write( "D:/test1.xml");
  }
}

优点

  1. 允许改变product的内部表示,定义一个新的builder即可。因为builder隐藏了product的表示和内部结构,也隐藏了product是如何组装的。
  2. 将构建和表示的代码分离开。将复杂对象的创建和表示封装起来,提供了模块化特性。每个ConcreteBuilder都定义了完整的创建和组装product的方法,不同的Director可以重用这些方法来构造不同的product。——也就是说可以替换Director,以便生成不同的product。
  3. 能更好地控制构建过程。并非一蹴而就地构建出product,而是在director的控制下一步一步地构建product。

缺点

适用场景

  1. 复杂对象的创建逻辑、其组成部分的创建逻辑、组装逻辑,互相独立。
  2. 构建过程允许对象有不同的表示。

诀窍

  • AbstractBuilder中的方法留空,而不定义成抽象方法。
这样ConcreteBuilder就能按需实现方法,而不是实现所有方法。
  • 为什么没有AbstractProduct?

一般ConcreteBuilder构建的product表示的差异很大。客户端会给director配置某个具体的ConcreteBuilder,所以客户端也就知道了会创建那种product。

  • 为何不把builder中的逻辑移到Product中:
让Product尽可能小,易于理解和修改;
逻辑分开后,可以定义多种builder,实现不同的逻辑

Related Patterns

  • Abstract Factory也是用来创建复杂对象,但是它着重于创建产品族;Builder则着重于一步一步地创建复杂对象。Builder是在最后一步返回product;而Abstract Factory立即返回product。
  • Builder通常用来构建Composite

猜你喜欢

转载自blog.csdn.net/vking_wang/article/details/16370467