一天一个设计模式---生成器模式
2016-09-27 21:33
309 查看
介绍:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
场景:我们在创建对象时可能会碰到过一个问题,比如,如果需要赋值的属性过多,构造函数会很多,而且有的会很长。通过JavaBean的方式可能不需要担心构造函数,但是,我们的set部分又会很长很难看,这里推荐大家试试builder模式
内部组件
可见,这种方式会使此类中存在很多构造方法,而且不能满足所有的组合,客户端在制作房屋的时候,比较不适用。
典型的java bean 的形式,解决上面构造函数的不足,但是让我们来看看使用。
如果我们的私有属性增加到二十,那么我们每次创建的时候就需要写二十行setter代码,累不累?
总结:
上面这两种方法,在每次创建房屋的时候,客户端还需要每次去创建各种类型的对象,会产生很多重复代码。
抽象生成器
生成器的具体实现:木屋
生成器的具体实现:别墅
build管理者
开始制作房子
输出
这样,我们可以明显感觉到在创建对象时候代码量少了很多。而且,对于不同款式的房子,我们只需要不同的Director,对象的属性和创建分离。
优点:
- 生产过程交给Director,客户端不必知道产品的内部结构
- 可以有多个生成器,方便扩展
创建对象的方法:
比较:
这个创建对象的方法就像Python中的具名的可选参数。
builder可以对参数加强约束条件,build方法可以用于检验这些约束。
与构造器相比,builder的优势在于可以有多个可变参数,builder参数可以在创建对象期间调整。
和setter相比,属性可以不可变,如上面NutFacts,属性都是不可变得final。但是通过构造器对Builer对象修改,又可以修改属性。
更多模式: 一天一个设计模式—分类与六大原则
更多源码: https://github.com/oDevilo/Java-Base
场景:我们在创建对象时可能会碰到过一个问题,比如,如果需要赋值的属性过多,构造函数会很多,而且有的会很长。通过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
相关文章推荐
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- 设计模式---状态模式在web前端中的应用
- Ruby设计模式编程之适配器模式实战攻略
- 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- Ruby设计模式编程中对外观模式的应用实例分析
- 实例解析Ruby设计模式编程中Strategy策略模式的使用
- Ruby中使用设计模式中的简单工厂模式和工厂方法模式
- Ruby使用设计模式中的代理模式与装饰模式的代码实例
- 详解组合模式的结构及其在Ruby设计模式编程中的运用
- C# 设计模式系列教程-建造者模式
- C#编程中使用设计模式中的原型模式的实例讲解
- 使用设计模式中的工厂方法模式进行C#编程的示例讲解
- 实例解析C#设计模式编程中简单工厂模式的使用