【笔记整理】图解设计模式 | 第7章 Builder模式(组装复杂的实例)

【笔记整理】图解设计模式 | 导航


定义

  • 组装具有复杂结构的实例。

Builder模式中的登场角色

  • Builder(建造者)
  • ConcreteBuilder(具体的建造者)
  • Director(监工),只调用在Builder角色中被定义的方法,不依赖于ConcreteBuilder角色如何实现。

Builder模式的类图


Builder模式的时序图


拓展思路的要点

  • 谁知道什么?

       这里强调了“可替换性”,因为可以替换,组件才具有高价值。

       Main类不知道Builder类,只知道调用了Director类的construct方法,就可以完成工作。

       Director类知道Builder类,但不知道具体使用了哪一个ConcreteBuilder类,由Main来传递进来,但是哪一个子类进来都可以执行程序。

  • 设计时能够决定的事情和不能决定的事情

       有必要让设计出的类能够尽可能灵活地应对近期可能发生的变化。

  • 代码的阅读方法和修改方法

       编程时,有时从零开始,但更多时候都是从现有代码的基础上进行增加和修改。

       彻底理解后再动手修改


相关的设计模式

       在Builder模式中,Director角色控制Builder角色方法调用的顺序(使用委托)。

       在Template Method模式中,父类控制子类方法调用的顺序(使用继承)。

  • Composite模式(第11章)

       有些情况下Builder模式生成的实例构成了Composite模式。

  • Abstract Factory模式(第8章)

       Builder模式和Abstract Factory模式都用于生成复杂的实例。

  • Facade模式(第15章)

       在Builder模式中,Director角色通过组合Builder角色中的复杂方法向外部提供可以简单生成实例的接口(API)(相当于示例程序中的construct方法)。

       Facade模式中的Facade角色则是通过组合内部模块向外部提供可以简单调用的接口(API)。


代码

  • Builder(建造者)
package build;

public abstract class Builder {

	private boolean initialized = false;

	public void makeTitle(String title) {
		if (!initialized) {
			buildTitle(title);
		}
		initialized = true;
	}

	public void makeString(String str) {
		if (initialized) {
			buildString(str);
		} else {
			System.out.println("未初始化");
		}
	}

	public void makeItems(String[] items) {
		if (initialized) {
			buildItems(items);
		} else {
			System.out.println("未初始化");
		}
	}

	public void close() {
		if (initialized) {
			buildDone();
		} else {
			System.out.println("未初始化");
		}
		// TODO close以后不能再调用其他方法
	}

	public abstract void buildTitle(String title);

	public abstract void buildString(String str);

	public abstract void buildItems(String[] items);

	public abstract void buildDone();
}
  • ConcreteBuilder(具体的建造者)
package build;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class FrameBuilder extends Builder implements ActionListener {

	private JFrame frame = new JFrame();
	private Box box = new Box(BoxLayout.Y_AXIS);

	@Override
	public void buildTitle(String title) {
		frame.setTitle(title);
	}

	@Override
	public void buildString(String str) {
		box.add(new JLabel(str));
	}

	@Override
	public void buildItems(String[] items) {
		Box innerbox = new Box(BoxLayout.Y_AXIS);
		for (int i = 0; i < items.length; i++) {
			JButton button = new JButton(items[i]);
			button.addActionListener(this);
			innerbox.add(button);
		}
		box.add(innerbox);
	}

	@Override
	public void buildDone() {
		frame.getContentPane().add(box);
		frame.pack();
		frame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println(e.getActionCommand());
	}

	public JFrame getResult() {
		return frame;
	}

}
package org.suych.db.build;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class HTMLBuilder extends Builder {

	private String filename;
	private PrintWriter write;

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

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

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

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

	public String getResult() {
		return filename;
	}

}
package build;

public class TextBuilder extends Builder {

	private StringBuffer buffer = new StringBuffer();

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

	@Override
	public void buildString(String str) {
		buffer.append('*' + str + "\n");
		buffer.append("\n");
	}

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

	@Override
	public void buildDone() {
		buffer.append("=======================\n");
	}

	public String getResult() {
		return buffer.toString();
	}
}
  • Director(监工)
package build;

public class Director {

	private Builder builder;

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

	public void construct() {
		builder.makeTitle("Greeting");
		builder.makeString("从早上至下午");
		builder.makeItems(new String[] { "早上好。", "下午好" });
		builder.makeString("晚上");
		builder.makeItems(new String[] { "晚上好。", "晚安。", "再见。" });
		builder.close();
	}
}
  • Main(调用者)
package build;

import javax.swing.JFrame;

public class Main {

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

		HTMLBuilder htmlBuilder = new HTMLBuilder();
		Director director2 = new Director(htmlBuilder);
		director2.construct();
		String filename = htmlBuilder.getResult();
		System.out.println(filename + "文件编写完成");

		FrameBuilder frameBuilder = new FrameBuilder();
		Director director4 = new Director(frameBuilder);
		director4.construct();
		JFrame frame = frameBuilder.getResult();
		frame.setVisible(true);
	}
}

注:博客中的图片来自网上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值