Java 无法使用工厂方法模式控制实例?

Java 无法使用工厂方法模式控制实例?,java,design-patterns,Java,Design Patterns,工厂的好处之一是它不必返回新对象。它可以从对象池返回对象 这很好,但是为了让工厂在需要时创建对象,这些对象类需要公共构造函数。因此,从理论上讲,有人可以直接到课堂上要求一个新的实例,而工厂对此一无所知。在工厂外创建的对象将不会添加到对象池中 有没有办法阻止在工厂外创建对象?您应该将您的类设置为其包的私有类您应该将您的类设置为其包的私有类或者您可以将您的实例类设置为工厂的私有嵌套类。或者您可以将您的实例类设置为私有类工厂的嵌套类。它们可以有受保护的构造函数,而不是公共构造函数。它们可以有受保护的构

工厂的好处之一是它不必返回新对象。它可以从对象池返回对象

这很好,但是为了让工厂在需要时创建对象,这些对象类需要公共构造函数。因此,从理论上讲,有人可以直接到课堂上要求一个新的实例,而工厂对此一无所知。在工厂外创建的对象将不会添加到对象池中


有没有办法阻止在工厂外创建对象?

您应该将您的类设置为其包的私有类

您应该将您的类设置为其包的私有类

或者您可以将您的实例类设置为工厂的私有嵌套类。

或者您可以将您的实例类设置为私有类工厂的嵌套类。

它们可以有受保护的构造函数,而不是公共构造函数。

它们可以有受保护的构造函数,而不是公共构造函数。

您可以做一些事情来在不同程度上控制对构造函数的访问:

  • 为类指定一个包作用域(默认)构造函数,并使该工厂存在于同一工厂中:如果这样做,则只有同一包中的类才能访问该构造函数。这应该足够好了

  • 使类成为工厂的私有内部类:这样做可以确保只有工厂才能使用它们

  • 不要在代码中做任何事情,但要编写一些好的文档,说明您认为客户应该使用工厂的原因:有时候,如果人们认为他们有充分的理由在您想象之外这样做,那么让他们开枪打自己的脚是可以的


  • 有几件事可以在不同程度上控制对构造函数的访问:

  • 为类指定一个包作用域(默认)构造函数,并使该工厂存在于同一工厂中:如果这样做,则只有同一包中的类才能访问该构造函数。这应该足够好了

  • 使类成为工厂的私有内部类:这样做可以确保只有工厂才能使用它们

  • 不要在代码中做任何事情,但要编写一些好的文档,说明您认为客户应该使用工厂的原因:有时候,如果人们认为他们有充分的理由在您想象之外这样做,那么让他们开枪打自己的脚是可以的


  • 是否有令人信服的理由阻止对象在工厂之外被实例化?这种控制通常是无效的。请记住,由于反思,你永远无法完全避免这种情况。你只是让它更烦人。如果是项目中的编码风格、性能或类似问题,最好使用静态分析工具,如,或在错误的位置观察对象实例化。

    是否有令人信服的理由阻止对象在工厂以外的地方实例化?这种控制通常是无效的。请记住,由于反思,你永远无法完全避免这种情况。你只是让它更烦人。如果是项目中的编码风格、性能或类似问题,最好使用静态分析工具,如,或在错误的位置观察对象实例化。

    我实际上不推荐以下内容,我可能自己也不会这样做

    话虽如此,您可以做的一件事是让所有对象检查它们是否由工厂构造,如果不是,则抛出一个合适的异常

    为此,在对象的构造函数中,只需调用
    Thread.currentThread().getStackTrace()
    ,然后“展开”堆栈,直到到达构造函数之后(之前)的帧。现在,您可以检查调用方并抛出异常(如果它不是
    工厂

    这种技术甚至可以防止通过反射实例化新的对象实例

    现在很明显,在检查和展开堆栈跟踪时会有开销,如果工厂不能插入/缓存以前构造的对象(即,它每次都必须返回一个新实例),并且您调用它的次数足够多,那么所有这些都会变得昂贵


    因此,通常的警告“仅仅因为它可以做到,并不意味着你应该做到”适用。再说一次,如果你真的必须这样做,那么至少知道一种方法是很好的。

    我并不推荐下面的方法,而且我自己可能永远也不会这样做

    话虽如此,您可以做的一件事是让所有对象检查它们是否由工厂构造,如果不是,则抛出一个合适的异常

    为此,在对象的构造函数中,只需调用
    Thread.currentThread().getStackTrace()
    ,然后“展开”堆栈,直到到达构造函数之后(之前)的帧。现在,您可以检查调用方并抛出异常(如果它不是
    工厂

    这种技术甚至可以防止通过反射实例化新的对象实例

    现在很明显,在检查和展开堆栈跟踪时会有开销,如果工厂不能插入/缓存以前构造的对象(即,它每次都必须返回一个新实例),并且您调用它的次数足够多,那么所有这些都会变得昂贵


    因此,通常的警告“仅仅因为它可以做到,并不意味着你应该做到”适用。再说一次,如果你真的必须这样做,那么最好至少知道一种方法。

    这对那些在软件包之外工作的人是有效的。然而,在软件包中工作的人必须意识到,你应该只通过工厂创建实例。然后你应该遵循@nerdytenor answer如果合理拥有软件包的人不知道他们应该使用工厂,那么你的通信量就更大了