您的位置:首页 > 其它

一天一个设计模式---生成器模式

2016-09-27 21:33 309 查看
介绍:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

场景:我们在创建对象时可能会碰到过一个问题,比如,如果需要赋值的属性过多,构造函数会很多,而且有的会很长。通过JavaBean的方式可能不需要担心构造函数,但是,我们的set部分又会很长很难看,这里推荐大家试试builder模式

一、角色及作用

角色作用
产品(Product)目标创建的复杂对象
抽象生成器(Builder)提供创建一个Product对象的各个组件的方法及返回Product对象的方法
具体生成器(ConcreteBuilder)实现Buidler接口的类。
管理者(Director)用于管理builder对象的工作

二、场景

玩过《我的世界》这类沙盒游戏的玩家,很多都是冲着其开放式的制作功能去的。比如,我们要建造一个房子就需要以下:墙,屋顶,门,床。但是这些东西的制作也十分麻烦。如果每次都让客户端来创建会需要很多代码

内部组件

// 床
public class Bed {
public Bed(String s) {
System.out.println(s);
}
}

// 门
public class Door {
public Door(String s) {
System.out.println(s);
}
}

// 屋顶
public class Roof {
public Roof(String s) {
System.out.println(s);
}
}

// 墙
public class Wall {
public Wall(String s) {
System.out.println(s);
}
}


1.使用构造函数的方式

public class House {
public Bed bed;
public Door door;
public Roof roof;
public Wall wall;

public House(Bed bed){
this.bed = bed;
}

public House(Bed bed,Door door){
this.bed = bed;
this.door = door;
}

// ......省略各种组合的构造函数

}


可见,这种方式会使此类中存在很多构造方法,而且不能满足所有的组合,客户端在制作房屋的时候,比较不适用。

2.使用setter方式

public class House {
public Bed bed;
public Door door;
public Roof roof;
public Wall wall;

// setter and getter
}


典型的java bean 的形式,解决上面构造函数的不足,但是让我们来看看使用。

House house = new House();
house.setBed(1);
// ......省略其它set方法


如果我们的私有属性增加到二十,那么我们每次创建的时候就需要写二十行setter代码,累不累?

总结:

上面这两种方法,在每次创建房屋的时候,客户端还需要每次去创建各种类型的对象,会产生很多重复代码。

三、使用builder模式

产品-房子

public class House {
public Bed bed;
public Door door;
public Roof roof;
public Wall wall;
}


抽象生成器

public interface Builder {

public void bed();

public void door();

public void roof();

public void wall();

public House getProduct();
}


生成器的具体实现:木屋

public class WoodHouseBuilder implements Builder {

private House house = new House();

@Override
public void bed() {
house.bed=new Bed("木床");
}

@Override
public void door() {
house.door = new Door("木门");
}

@Override
public void roof() {
house.roof = new Roof("木头屋顶");
}

@Override
public void wall() {
house.wall = new Wall("木墙");
}

@Override
public House getProduct() {
return house;
}

}


生成器的具体实现:别墅

public class VillaHouseBuilder implements Builder {

private House house = new House();

@Override
public void bed() {
house.bed = new Bed("木床");
}

@Override
public void door() {
house.door = new Door("铁门");
}

@Override
public void roof() {
house.roof = new Roof("欧式带天窗屋顶");
}

@Override
public void wall() {
house.wall = new Wall("石墙");
}

@Override
public House getProduct() {
return house;
}

}


build管理者

public class Director {
private Builder builder;

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

public void construct() {
builder.wall();
builder.roof();
builder.door();
builder.bed();
}
}


开始制作房子

public static void main(String[] args) {
System.out.println("开始做木屋=======");
Builder builder = new WoodHouseBuilder();
Director director = new Director(builder);
director.construct();
System.out.println("开始做别墅=======");
Builder builder2 = new VillaHouseBuilder();
director = new Director(builder2);
director.construct();
}


输出

开始做木屋=======
木墙
木头屋顶
木门
木床
开始做别墅=======
石墙
欧式带天窗屋顶
铁门
木床


这样,我们可以明显感觉到在创建对象时候代码量少了很多。而且,对于不同款式的房子,我们只需要不同的Director,对象的属性和创建分离。

优点:

- 生产过程交给Director,客户端不必知道产品的内部结构

- 可以有多个生成器,方便扩展

四、《Effective Java》中的Builder模式

在《Effective Java》中也有对Builder模式的使用,但是感觉在实现上和上面还是有点区别。参考:《Effective Java》 第二章,第2条:遇到多个构造器参数时要考虑用构造器

public class NutFacts {
private final int serSize;
private final int fat;
private final int car;
private final int so;

public static class Builder {

// 必填字段
private final int serSize;

// 非必填字段
private int fat = 0;
private int car = 0;
private int so = 0;

public Builder(int serSize) {
this.serSize = serSize;
}

public Builder fat(int val) {
fat = val;
return this;
}

public Builder car(int val) {
car = val;
return this;
}

public Builder so(int val) {
so = val;
return this;
}

public NutFacts build() {
return new NutFacts(this);
}
}

private NutFacts(Builder builder) {
serSize = builder.serSize;
fat = builder.fat;
car = builder.car;
so = builder.so;
}
}


创建对象的方法:

NutFacts no = new NutFacts.Builder(1).car(2).so(1).build();


比较:

这个创建对象的方法就像Python中的具名的可选参数。

builder可以对参数加强约束条件,build方法可以用于检验这些约束。

与构造器相比,builder的优势在于可以有多个可变参数,builder参数可以在创建对象期间调整。

和setter相比,属性可以不可变,如上面NutFacts,属性都是不可变得final。但是通过构造器对Builer对象修改,又可以修改属性。

更多模式: 一天一个设计模式—分类与六大原则

更多源码: https://github.com/oDevilo/Java-Base
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式