为什么构建器应该是内部类而不是其自己的类文件中?


24

许多Builder Pattern示例都将Builder其构建为对象的内部类。

这有一定道理,因为它表明了Builder构建的内容。但是,使用静态类型的语言,我们知道Builder构建的内容。

另一方面,如果Builder是内部类,则应了解Builder构建的类,而无需查看内部Builder

而且,将构建器作为内部类可以减少导入的次数,因为外部类可以引用该构建器(如果您对此很在意)。

然后是一些实际的示例,其中Builder放在同一包中,而不是内部类(如)StringBuilder。您知道Builder 应该建立一个,String因为它名为so。

话虽这么说,我能想到的制作Builder内部类的唯一好理由是,您Builder无需知道类的名称或依赖命名约定就可以知道类的含义。例如,如果我StringBuilder是一个内部类,String我可能会知道它比我(推测性)早存在。

是否有其他原因可以使Builder内部类成为阶级,或者只是归结为偏好和仪式?

Answers:


30

我认为这样做的原因是为了使内部类(构建器)可以访问其正在构建的类的私有成员。

来自http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有的也是如此。

...

考虑两个顶级类A和B,其中B需要访问A的成员,否则将其声明为私有。通过将类B隐藏在类A中,可以将A的成员声明为私有,而B可以访问它们。

...

与实例方法和变量一样,内部类与其所在类的实例相关联,并且可以直接访问该对象的方法和字段。

这是一些代码来说明这一点:

class Example {

    private int x;

    public int getX() { return this.x; }

    public static class Builder {

        public Example Create() {
            Example instance = new Example();
            instance.x = 5; // Builder can access Example's private member variable
            return instance;
        }
    }
}

作为静态类,Builder没有与之关联的Example的特定实例。但是,给定Example实例(或其创建的实例)后,Builder仍可以访问该实例的私有成员。


很好的答案,这是有道理的!但是,构建器模式通常具有静态内部类,并且仅能够访问外部类的静态私有成员。如果您有一个用于实例化类的构建器,那将是很奇怪的。
纳撒尼尔(Nathanial)2014年

1
@Nathanial根本没有,私有实例变量也可以访问:ideone.com/7DyjDR
amon

1
@nathanial:是的,但是构建器没有操纵该类;它正在操纵构建器本身已实例化的类的对象。
罗伯特·哈维

@amon我明白你在那里做了什么。感谢您的解释!
纳撒尼尔(Nathanial)2014年

具体来说,它使构建器可以访问正在构建的类的私有构造器,从而使该类是不可变的(所有字段均为最终字段),并且只能通过构建器实例化。
马修·麦克佩克

1

在这种情况下,没有“应该”。在另一个类中定义构建器或将其分开与构建器模式正交。由于方便地将代码显示在一个一致的文件中(也用于访问私有成员,但这也取决于上下文),因此许多示例都这样做了。随意做否则


除了“因为这不是我们在Java中的处理方式,”以外的其他原因,不知道为什么这个答案被否决了。构建器模式为采用一堆参数的构造函数提供了包装。如果构造函数采用这些参数,则不需要Builder对象访问私有成员。
格雷格·伯格哈特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.