组装复杂的实例
1.基本介绍
对于组件复杂的实例时,很难一气呵成,而且实例形式不定,会经常性变化,这时候就需要创建组成实例的各个部分,然后根据具体需求,分阶段将其组装起来,如同活字印刷术,或者建造建筑。
2.具体实现
Builder类:
/**
* @author Jay
* @date 2019/6/25 22:41
* @description 声明编写文档方法的抽象类
*/
public abstract class Builder {
public abstract void makeTitle(String title);
public abstract void makeString(String str);
public abstract void makeItems(String[] items);
public abstract void close();
}
Director类:
将抽象父类或者接口作为参数传递,实现解耦。方法中具体制定了整个实例的拼接的规范,如同设计图纸,规定每一块材料如何具体拼接。
/**
* @author Jay
* @date 2019/6/25 22:42
* @description 使用Bulider中声明方法写文档
*/
public class Director {
/**
* 可将子类实例保存其中
*/
private Builder builder;
/**
* 抽象类无法实例化对象,可以接收其子类实例.
*
* @param builder
*/
public Director(Builder builder) {
super();
this.builder = builder;
}
/**
* 编写文档
*/
public void construct() {
builder.makeTitle("Greeting");
builder.makeString("从早到下午");
builder.makeItems(new String[]{
"早上好",
"下午好"
});
builder.makeString("晚上好");
builder.makeItems(new String[]{
"晚上好",
"再见!"
});
builder.close();
}
}
TextBuilder类:
继承抽象父类,具体实现其中的抽象方法,如同建筑中将每一块砖,每一个模型造好,然后设计者利用这些组件区设计整个建筑。
/**
* @author Jay
* @date 2019/6/25 22:44
* @description Builder子类, 纯文本写文档
*/
public class TextBuilder extends Builder {
private StringBuffer buffer = new StringBuffer();
/**
* 标题
*
* @param title
*/
@Override
public void makeTitle(String title) {
buffer.append("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
buffer.append("(" + title + ")\n");
buffer.append("#############################\n");
buffer.append("\n");
}
/**
* 内容
*
* @param str
*/
@Override
public void makeString(String str) {
buffer.append("$" + str + "\n");
buffer.append("\n");
}
/**
* 条目
*
* @param items
*/
@Override
public void makeItems(String[] items) {
for (String string : items) {
buffer.append("##" + string + "\n");
}
buffer.append("\n");
}
@Override
public void close() {
buffer.append("%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
}
/**
* 输出文档
*
* @return
*/
public String getResult() {
return buffer.toString();
}
}
Main:
/**
* @author Jay
* @date 2019/6/25 22:51
* @description
*/
public class Main {
public static void main(String[] args) {
//实例化组件对象
TextBuilder tb = new TextBuilder();
//将其作为参数传递进去,组装方法调用组件对象的具体组件去组装
Director di = new Director(tb);
//调用组装方法
di.construct();
System.out.println(tb.getResult());
}
}
3.主要角色
Builder(建造者)
定义用来生成实例方法的接口,其中定义各种组件。
ConcreteBuilder(具体建造者)
具体实现接口中的方法,定义了在生成实例时实际被调用的方法,每一个组件的具体实现.
其中还有获取最终结果的方法。
Director(监工)
负责使用Builder接口来生成实例,接收Builder参数,只调用Builder接口中被定义的方法,不论ConcreteBuilder中如何具体实现组件,都可以正常实现,就如同设计图纸一样,不管组件如何具体实现,只要实现了接口,都可以通过接口方法来进行组装,接口,是一种规范!
4.模式改进
上述例子中,可以将Director类省略,直接生成实例,通过链式结构,随意组装对象,并不需要通过修改Director中的对象生成方法,从而进一步解耦。
Builder:
/**
* @author Jay
* @date 2019/6/25 23:03
* @description 声明编写文档方法的接口
*/
public interface Builder {
Builder makeTitle(String title);
Builder makeString(String str);
Builder makeItems(String[] items);
Builder close();
}
TextBuilder类:
/**
* @author Jay
* @date 2019/6/25 23:06
* @description
*/
public class TextBuilder implements Builder {
/**
* 文档内容保存在其中
*/
private StringBuffer buffer = new StringBuffer();
public TextBuilder() {
super();
}
@Override
public Builder makeTitle(String title) {
buffer.append("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
buffer.append("(" + title + ")\n");
buffer.append("#############################\n");
buffer.append("\n");
//直接将实例本身返回,实现链式调用
return this;
}
@Override
public Builder makeString(String str) {
buffer.append("$" + str + "\n");
buffer.append("\n");
return this;
}
@Override
public Builder makeItems(String[] items) {
for (String string : items) {
buffer.append("##" + string + "\n");
}
buffer.append("\n");
return this;
}
@Override
public Builder close() {
buffer.append("%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
return this;
}
public String getResult() {
//变化为String
return buffer.toString();
}
}
main
/**
* @author Jay
* @date 2019/6/25 23:11
* @description
*/
public class Main {
public static void main(String[] args) {
TextBuilder tb = (TextBuilder) new TextBuilder().makeTitle("这是一个标题")
.makeString("这是一个字符串").makeItems(new String[]{"这是第一条数据"})
.makeItems(new String[]{"这是第二条数据",
"这是第三条数据",
"这是第四条数据"
}).makeTitle("再加一个标题").makeString("最后一个字符").close();
System.out.println(tb.getResult());
}
}
(这是一个标题)
#############################
$这是一个字符串
##这是第一条数据
##这是第二条数据
##这是第三条数据
##这是第四条数据
(再加一个标题)
#############################
$最后一个字符
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
省略制定设计图纸的类,直接在测试类中生成具体所需的类,实现链式调用,进一步解耦,实例生成也更为灵活,不过每一个方法都会返回实例,并且为公有方法,外界可以直接调用,因此可以改进使用内部类,更为安全。
/**
* @author Jay
* @date 2019/6/25 23:14
* @description
*/
public class Student {
private final int age;
private final int weight;
private final int height;
private final int size;
private final String name;
@Override
public String toString() {
return "Student [age=" + age + ", weight=" + weight + ", height=" + height + ", size=" + size + ", name=" + name
+ "]";
}
/**
* 创建静态内部类
* 属性都有默认值,若是未定义则是默认值,再次定义会将其覆盖
*/
public static class Bulider {
private final int age;
private final int weight;
private int height = 0;
private int size = 0;
private String name = null;
public Bulider(int age, int weight) {
this.age = age;
this.weight = weight;
}
public Bulider heiht(int val) {
//每次返回本身实例,则可以实现属性随意组合,
height = val;
return this;
}
public Bulider size(int val) {
size = val;
return this;
}
public Bulider name(String val) {
name = val;
return this;
}
public Student bulid() { //最后调用此方法会生成所需实例
return new Student(this);
}
}
private Student(Bulider bulider) { //私有构造属性,外界无法调用,内部类可以调用
age = bulider.age;
height = bulider.height;
size = bulider.size;
name = bulider.name;
weight = bulider.weight;
}
public static void main(String[] args) {
Student stu = new Student.Bulider(18, 2).heiht(20).name("张三").bulid();
System.out.println(stu);
}
}