专栏首页Java升级之路设计之禅——生成器模式

设计之禅——生成器模式

概述

Java是一门面向对象的语言,所以在使用它的时候我们首先就需要new一个对象,在创建一个简单对象new当然是没有任何问题的,但是在实际项目中我们往往需要构建一个个复杂的对象,且当某个对象需要多次创建时,我们再通过new去创建,不仅会产生大量冗余代码,而且极不利于维护(想象一下,某个多处被引用的对象需要修改内部属性,那么所有创建对象的代码都需要改变,简直是场灾难)。因此,生成器模式就出现了。

定义

生成器模式对外暴露一个接口,当调用此接口便自动创建好所需对象。它将对象固定的创建流程和其组件的具体实现解耦,使得客户可以专注于组件的实现。

通过类图我们不难发现生成器模式包含了四个角色,主导者、产品、抽象生成器接口以及具体生成器接口,需要注意的是产品最终是从具体生成器获取的而不是主导者。举个例子,比如你要修房子,房子包含了门、窗、墙等等,那你首先要找一队工人和设计师,这里工人就是具体的生成器,设计师则是主导者,由设计师告诉工人该做什么,也就是建造流程,具体怎么修建完成则是工人的事,最终房子修好了你是去找工人要,而不是找设计师要。

Coding

生成器模式的实现有两种,一种是按固定顺序构建,另一种是无序构建,先来看看第一种:

public class Room {

    private String door;
    private String window;
    private String floor;

    public void setDoor(String door) {
        this.door = door;
    }
    public void setWindow(String window) {
        this.window = window;
    }
    public void setFloor(String floor) {
        this.floor = floor;
    }
}

生成器族:

public interface Builder {

    Room room = new Room();

    void makeDoor(String door);

    void makeWindow(String window);

    void makeFloor(String floor);

    default Room getRoom() {
        return room;
    }

}

public class RoomBuilder implements Builder {

    @Override
    public void makeDoor(String door) {
        room.setDoor(door);
    }

    @Override
    public void makeWindow(String window) {
        room.setWindow(window);
    }

    @Override
    public void makeFloor(String floor) {
        room.setFloor(floor);
    }
}

主导者:

public class Designer {

    private Builder builder;

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

    public void build(String door, String window, String floor) {
        builder.makeDoor(door);
        builder.makeDoor(window);
        builder.makeFloor(floor);
    }

}

最后测试:

public static void main(String[] args) {
        Builder builder = new RoomBuilder();
        Designer designer = new Designer(builder);
        designer.build("door", "window", "floor");
        Room room = builder.getRoom();
}

如果产品的生成需要按照固定的顺序构建就可以采用上述的实现方式,而当需要灵活设置产品属性时就可以采用静态内部类的方式来实现无序的生成器模式,代码如下:

public class Room {

    private String door;
    private String window;
    private String floor;

    public Room(Builder builder) {
        this.door = builder.door;
        this.floor = builder.floor;
        this.window = builder.window;
    }

    public static class Builder {
        private String door;
        private String window;
        private String floor;

        public Builder makeDoor(String door) {
            this.door = door;
            return this;
        }
        public Builder makeWindow(String window) {
            this.window = window;
            return this;
        }
        public Builder makeFloor(String floor) {
            this.floor = floor;
            return this;
        }

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

}

测试

public static void main(String[] args) {
        Room room = new Room.Builder().makeDoor("door").makeWindow("window").makeFloor("floor").build();
}

可以看到这种方式更加简洁明了,并且用户可以自行设置所需属性,所以在《Effective Java 第2版》中也是推荐用来替代重叠构造器模式JavaBean模式

当遇到需要重载多个构造器时,考虑用生成器模式来实现,它既保证了代码的整洁可阅读性,还可以避免JavaBean模式的不安全。

所谓重叠构造器模式也就是根据产品的必须属性和可选属性重载多个构造器,这种方式不好的就是当属性多了后代码就难以阅读,用户也难以正确选择构造器;JavaBean模式即我们常用的setter方法,这种方式好在于可以灵活的选择属性,但却无法保证安全性,尤其在多线程环境下,一个线程new完对象还未调用setter时,另一个线程就调用getter,就无法保证类的一致性;并且该方式产生的重复代码也非常多,所以当遇到需要多个构造器的情况下,考虑使用生成器模式

总结

生成器模式也是平时常用到的,弄清楚它的两种实现方式,在实际项目中遇到需要构建复杂对象时考虑使用它吧。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 设计之禅——享元模式

    之前已经写了17篇关于设计模式的文章,而这些设计模式大都是为了降低代码之间的耦合,避免违反开闭原则,但它们大都有同样的一个缺点,产生更多的类和对象,如果数量达到...

    夜勿语
  • Zookeeper——基本使用以及应用场景(手写实现分布式锁和rpc框架)

    在之前的文章主要讲述了Zookeeper的原理,本文则是实践,包含Zookeeper单机环境到集群环境的搭建,基本配置,JavaAPI的使用以及手写实现分布式锁...

    夜勿语
  • 设计之禅——外观模式

    平时在我们生活中,我们常常会接触学习各种各样的新事物,而能够快速吸引留住大量客户的都有一个共性,就是简单易学好上手。比如,windows和linux系统,前者比...

    夜勿语
  • Android开发:Android Studio插件GsonFormat根据Json自动生成javabean的方法

    在Android开发过程中,会创建多个javabean,在App网络请求多的时候,一个列表数据就需要新建一个javabean。而且javabean中好多重复的方...

    三掌柜
  • 科普任重而道远:生物信息为什么要学 Linux?

    生物信息学是真正的大数据专业,对计算资源要求较大,很多时候需要在服务器上分析数据,而 Linux 是最常用的服务器操作系统。

    简说基因
  • linux添加/修改ssh默认端口

    Windows服务器上,我们会使用远程桌面来管理服务器。而在linux服务器,我们一般通过SSH来进行远程登录,管理服务器。

    ianzhi
  • 【JAVA代码审计】——1、Spring框架知识篇

    本期Java代码审计Spring框架知识篇将讲述Spring构造POC要必备的知识。

    用户7886150
  • Java支付宝接口开发【面试+工作】

    Java支付宝接口开发【面试+工作】 最近公司在做支付模块,在接入过程中遇到了很多坑,费了不少事,现在分享一下接入方法,也记录一下,以后可能还用的到。用的是支付...

    Java帮帮
  • Redis做分布式无锁CAS的问题 顶

    因为Redis本身是单线程的,具备原子性,所以可以用来做分布式无锁的操作,但会有一点小问题。

    算法之名
  • 一个通用的Java正则匹配工具

    一个通用且常用的Java正则匹配工具,用以检查邮箱名、电话号码、用户密>码、邮政编码等合法性。 验证Email @param email email地址,格式:...

    用户1263308

扫码关注云+社区

领取腾讯云代金券