缺少“框架级别”访问修饰符

时间:2012-05-18 13:51:45

标签: java access-modifiers

这是场景。作为公开许可的开源API的创建者,我的小组已经创建了一个基于Java的Web用户界面框架(那么还有什么是新的?)。为了使Java保持良好和有条理,我们使用了具有命名约定的包 org.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的内部而非 其公共API的一部分。不要打电话!!!!!!“一些研究表明这些方法是从框架内的其他地方调用的。

事实上,我是一名使用相关框架的开发人员。虽然我们的应用程序已经部署并且取得了成功,但我的团队遇到了很多挑战,我们希望说服我们的老板再也不要使用这个框架了。我们希望通过对框架开发人员做出的糟糕设计决策的深思熟虑的演示来做到这一点,而不仅仅是作为一个咆哮。这个问题将是我们的一个(几个)问题,但我们无法指出我们如何以不同的方式做到这一点。我的工作场所已经有了一些热烈的讨论,所以我想知道世界其他人会怎么想。


更新:到目前为止,两位回答者没有冒犯,但我认为你错过了这个标记,或者我没有表达好。无论哪种方式,我都可以尝试照亮事物。尽可能简单地说,框架的开发人员应该如何重构以下内容。请注意,这是一个非常粗略的例子。

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中模拟/模拟内部访问?”不过,我并不是在寻找新的答案。我们的老板最终同意上述问题

4 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

Java语言中没有这种访问级别的支持(你想要像命名空间的“内部”一样)。您只能限制对包级别(或已知的继承公共保护 - 私有模型)的访问。

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

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

答案 2 :(得分:0)

接口和动态代理有时用于确保只公开您想要公开的方法。

然而,如果经常调用您的方法,则会产生相当大的性能成本。

使用@Deprecated注释也可能是一个选项,虽然它不会阻止外部用户调用“框架私有”方法,但他们不能说它们没有被警告过。

一般情况下,我认为你不应该担心你的用户故意在脚下过多地射击自己,只要你向他们说明他们不应该使用某些东西。

答案 3 :(得分:0)

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

当然,即使你确实拥有细粒度的权限,你仍然无法阻止客户端模块调用内部方法--- jvm无法防止基于反射的私有方法调用

我使用的方法是为每个有问题的类定义一个接口,并让类实现它。界面可以仅根据客户端模块进行记录,而实现类可以提供您需要的内部文档。如果你不想,你甚至不必在你的分发包中包含实现javadoc,但是无论哪种方式都明确划分了边界。

只要您确保在运行时每个文档界面只加载一个实现,现代的jvm将保证您不会因使用它而遭受任何性能损失;并且,您可以在测试期间加载线束/存根版本以获得额外的奖励。