Java “失踪者”;“框架级”;访问修饰符

Java “失踪者”;“框架级”;访问修饰符,java,access-modifiers,Java,Access Modifiers,下面是一个场景。作为一个公开许可的开源API的创建者,我的团队创建了一个基于Java的web用户界面框架(那么还有什么新的吗?)。为了在Java中保持良好的组织,我们使用了具有命名约定的包 mygroup.myframework.x,其中x是组件、验证器、转换器、实用程序等(再说一遍,还有什么新功能?) 现在,在org.mygroup.myframework.foo.Bar类的某个地方有一个方法void doStuff(),我需要执行特定于我的框架的逻辑,并且我需要能够从框架中的一些其他地方调用

下面是一个场景。作为一个公开许可的开源API的创建者,我的团队创建了一个基于Java的web用户界面框架(那么还有什么新的吗?)。为了在Java中保持良好的组织,我们使用了具有命名约定的包 mygroup.myframework.x,其中x是组件、验证器、转换器、实用程序等(再说一遍,还有什么新功能?)

现在,在org.mygroup.myframework.foo.Bar类的某个地方有一个方法
void doStuff()
,我需要执行特定于我的框架的逻辑,并且我需要能够从框架中的一些其他地方调用它,例如org.mygroup.myframework.far.Boo。鉴于Boo既不是Bar的子类,也不在完全相同的包中,因此方法doStuff()必须声明为public,才能由Boo调用

然而,我的框架作为一种工具存在,允许其他开发人员为他们的客户创建更简单、更优雅的R.I.a.s。但是如果com.yourcompany.yourapplication.YourComponent调用doStuff(),可能会产生意想不到的不良后果。我会的 我更希望这种情况永远不会发生请注意,Bar包含其他真正公开的方法。

在象牙塔世界中,我们将重新编写Java语言,并插入一个标记化的模拟默认访问,这将允许我们选择的包结构中的任何类访问我的方法,可能看起来类似于:

[org.mygroup.myframework.*] void doStuff() { .... }
其中通配符表示包以org.mygroup.myframework开头的任何类都可以调用,但其他任何类都不能调用

既然这个世界不存在,我们还有什么好的选择呢


请注意,这是由现实生活场景驱动的;为了保护罪犯,名字已经改了。存在一个真正的框架,在它的Javadoc中,人们会发现公共方法被注释为“此方法是MYFRAMEWORK的内部方法,而不是 “一些研究表明,这些方法是从框架内的其他地方调用的

事实上,我是一名使用该框架的开发人员。虽然我们的应用程序已经部署并取得了成功,但我的团队经历了太多的挑战,我们希望说服我们的老板不再使用此框架。我们希望通过对框架开发人员所做的糟糕设计决策进行深思熟虑的展示来做到这一点,而不仅仅是作为一种咆哮。这个问题可能是我们的观点之一,但我们无法确定我们可能会采取什么不同的做法。在我的工作场所已经有了一些热烈的讨论,所以我想知道世界上其他人会怎么想


更新:到目前为止,没有冒犯两位回答者,但我认为你没有抓住重点,或者我没有很好地表达出来。无论哪种方式,请允许我尝试阐明一些事情。简单地说,框架的开发人员应该如何重构以下内容。请注意,这是一个非常粗略的示例

package org.mygroup.myframework.foo;
public class Bar {
     /** Adds a Bar component to application UI */
     public boolean addComponentHTML() {
         // Code that adds the HTML for a Bar component to a UI screen
         // returns true if successful
         // I need users of my framework to be able to call this method, so
         // they can actually add a Bar component to their application's UI
     }

     /** Not really public, do not call */
     public void doStuff() {
         // Code that performs internal logic to my framework
         // If other users call it, Really Bad Things could happen!
         // But I need it to be public so org.mygroup.myframework.far.Boo can call
     }
}


另一个更新:我刚刚了解到C#具有“内部”访问修饰符。因此,也许更好的表达这个问题的方式是“如何在Java中模拟/模拟内部访问?”尽管如此,我并不是在寻找新的答案。我们的老板最终同意了上述担忧

为了提供这个缺失的“框架级访问修改器”,我能想到的唯一想法是CDI和更好的设计。
如果您必须在各种(但很少)情况下使用来自非常不同的类和包的方法,那么肯定会有一种方法重新设计这些类,以使这些方法“私有”且不可访问。

Java语言不支持这种访问级别(您希望类似于名称空间的“内部”)。您只能限制对包级别(或已知的继承受公共保护的私有模型)的访问

根据我的经验,您可以使用Eclipse约定: 创建一个名为“internal”的包,该包的所有类层次结构(包括子包)都将被视为非API代码,并且可以随时更改,而不保证您的用户。在非API代码中,可以随时使用公共方法。由于它只是一种约定,并且不是由JVM或Java编译器强制执行的,因此您不能阻止用户使用代码,但至少要让他们知道这些类不是第三方使用的


顺便说一句,在Eclipse平台源代码中,有一个复杂的插件模型,它通过为每个插件实现自定义类加载器来强制您不要使用其他插件的内部代码,从而防止加载应该是“内部”的类在这些插件中。

接口和动态代理有时用于确保只公开您确实希望公开的方法

然而,如果您的方法经常被调用,那么这将带来相当大的性能代价

使用
@Deprecated
注释也可能是一种选择,尽管它不会阻止外部用户调用“框架私有”方法,但他们不能说没有收到警告


总的来说,我认为你不应该担心你的用户故意用枪打自己的脚,只要你清楚地告诉他们不应该使用某些东西。

当你提到文档问题时,你就最接近答案了。真正的问题不是你不能“保护”你的内部方法;相反,内部方法污染了您的文档,并引入了客户机模块可能错误调用内部方法的风险

当然,即使您确实拥有细粒度的权限,您仍然无法阻止客户端模块调用内部方法——jvm无论如何都不能防止对私有方法的基于反射的调用

我使用的方法是为每个有问题的类定义一个接口,