Java 生成器设计模式

10 阅读5分钟

生成器

 

这是一种专门负责创造对象的类,也是工厂方法设计模式的一种应用。与之不同的是,生成器生成对象时不需要任何参数,而工厂方法需要参数。简而言之,生成器无需额外的信息就知道如何创建新的对象。

 

一般而言,一个生成器只定义一个方法,用来产生新的对象。

 

public interface Generator<T> {  
    T next();  
}

 

使用泛型使生成器能够生成所有类型的对象,只要你实现了这个接口并且传入需要的类型。

 

 

接下来我们来实现一个通用的Generator类,它实现了Generator接口,并重写了next方法。

 

 

 

public class BasicGenerator<T> implements Generator<T>{

    private Class<T> type;

    public BasicGenerator(Class<T> type) {\
        this.type = type;
    }

    @Override\
    public T next() {
        // 被弃用的旧方法,原因是会抛出受检异常而不是具体的异常信息,同时绕过了编译检查
    
        try {
            return type.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

        // 推荐使用下面的新方法
        try {
            Constructor<T> constructor = type.getDeclaredConstructor();
            return constructor.newInstance();
        } catch (NoSuchMethodException e) {
            // type类缺少无参构造器
        } catch (InvocationTargetException e) {
            // 构造器抛出异常
        } catch (InstantiationException e) {
            // 无法实例化抽象类或者接口
        } catch (IllegalAccessException e) {
            // 无法访问构造器
        }
        return null;
    }

    // 创建BasicGenerator的方法,免于调用时麻烦的参数输入
    public static <T> Generator<T> create(Class<T> type) {
        return new BasicGenerator<T>(type);
    }
}

 

如果我们希望某个类可以被生成,那么这个类需要具备两个要点:必须具备默认的无参构造器、类必须声明为public。

 

我们一条条来说明:

 

因为BasicGenerator类和要生成对象的类并不会在同一个包内,所以需要该类必须声明为public,并且不只具有包内的访问权限。

constructor.newInstance() 方法调用的是type类的无参构造器,所以必须要有默认的无参构造器,不然就会抛出NoSuchMethodException异常。

 

 

你或许会发现constructor对象还有这么一个方法:constructor.setAccessible(true),顾名思义,这个方法看上去像是授权的,实际上也的确如此。constructor.setAccessible(true)方法是 Java反射中的一个方法,用于绕过 Java的访问控制检查,允许你访问 private、protected 或包私有的成员(字段、方法、构造器)。这是一个十分强大的方法,常用于各大框架和序列化、单元测试中,比如spring的依赖注入,@AutoWired 注解的一般都是私有成员,就是靠这个权限才能够正常将需要的对象插入进成员内。当然,副作用也有很多,最直观的就是会破坏单例,可以强制调用私有构造器生成第二个对象。我们所创建的这个生成器自然没有必要开启这项权限,毕竟生成器需要用到这个权限的场景大概只有破坏单例了。

 

 

有了生成器,便可以使用生成器自由的创建各种对象了,下面是一些例子。

 

class GenshinImpact {
    public GenshinImpact() {
        System.out.println("GenshinImpact Start!");
    }
}

public class BasicGeneratorDemo {
    public static void main(String[] args) {

// 调用create方法创建生成器
        Generator<GenshinImpact> gen = BasicGenerator.create(GenshinImpact.class);

// 调用生成器方法创建对象实例,调用无参构造器。
        GenshinImpact genshinImpact = gen.next();
    }
}

 

控制台输出,证明调用

屏幕截图 2026-06-10 220015.png

 

 

还可以写一个随机对象生成器用来愉悦心情

 

import java.util.Random;

class MiHoYo {
    public MiHoYo() {
        System.out.println("MiHoYo什么的,最讨厌了");
    }
}

class GenshinImpact extends MiHoYo{
    public GenshinImpact() {
        System.out.println("GenshinImpact Start!");
    }
}

class HonkaiImpact extends MiHoYo{
    public HonkaiImpact() {
        System.out.println("HonkaiImpact Start!");
    }
}

class StarRail extends MiHoYo{
    public StarRail() {
        System.out.println("StarRail Start!");
    }
}

class ZZZ extends MiHoYo{
    public ZZZ() {
        System.out.println("ZZZZZZZZ");
    }
}

public class BasicGeneratorDemo {
    private static final Class[] types = {MiHoYo.class, GenshinImpact.class, HonkaiImpact.class, StarRail.class, ZZZ.class};
    private static Random random = new Random();
    public static void main(String\[] args) {
        for (int i = 0; i < 3; i++) {
            Class type = types[random.nextInt(types.length)];
            Generator gen = BasicGenerator.create(type);
            MiHoYo next = (MiHoYo) gen.next();
            System.out.println(next);
        }

    }
}

 

 

一种输出:

image.png

当然,用作正事的时候,数组中装载的就是需要的类了

 

 

 

看到这里有人就又要问了,欸,那你生成器也就生成个对象,好像和直接把对象new出来区别也不大嘛,那为什么还需要费劲创建一个生成器呢?

 

 

生成器本质上就是把"创建对象"这个动作抽象化、参数化、可替换化。在简单示例里它确实没啥用,但在框架、库和复杂系统里,这种抽象价值巨大。它的真正作用在当我们无法直接new出对象的时候。试想一下,如果不知道要创建什么对象,单纯的new还能解决创建对象的问题吗?不能。new是将代码写死,而生成器使用泛型,在运行时动态决定创建什么类型的对象,让代码活了过来。

如果需要创建的对象有很多个配置变量(比如数据库连接池),传统new对象时每创建一次都要重新写一遍配置信息,不仅麻烦,修改的时候工作量也是巨大。而使用生成器,我们只需要创建一个类继承生成器接口,便可以在类的构造器里单独配置所有变量,一次封装,无数次使用,省心又省力。

再比如,当我们希望控制某个类创建的对象总数的时候,便可以在对应类生成器的next方法中添加规则,规定如果对象数量达到上限,则返回已有对象,否则继续new新对象。

 

生成器设计模式将创建对象这一操作封装为一个方法,并可以设定对象成员变量的初始值和控制对象数量,在面对复杂对象和复杂要求时效果显著。