我多次遇到的一件事是服务类(如 JBoss 服务)由于助手内部类而变得过大。我还没有找到一个好的方法来打破课堂。这些助手通常是线程。这是一个例子:
/** Asset service keeps track of the metadata about assets that live on other
* systems. Complications include the fact the assets have a lifecycle and their
* physical representation lives on other systems that have to be polled to find
* out if the Asset is still there. */
public class AssetService
{
//...various private variables
//...various methods
public AssetService()
{
Job pollerJob = jobService.schedule( new AssetPoller() );
Job lifeCycleJob = jobService.schedule( AssetLifecycleMonitor() );
}
class AssetPoller
{
public void run()
{
// contact remote systems and update this service's private variables that
// track the assets.
}
}
class AssetLifecycleMonitor
{
public void run()
{
// look for assets that have meet criteria for a lifecycle shift
// and update this service's private variables as relevant.
}
}
}
因此,如果我有几个助手并且它们非常复杂,那么会发生什么,整个类文件会变得非常大。我喜欢内部类,因为它清楚地表明这些类完全归服务所有,并且存在只是为了帮助该服务。我尝试将类分解并传递父服务作为参考,这大部分有效,但我不喜欢的是:
我最终公开了包级访问器,以便分解的类可以访问变量,而在此之前我根本没有公开设置器,因为内部类可以直接访问。
另外,由于我不断调用访问器而不是底层变量,事情变得更加冗长。一个小问题,理所当然。
便捷方法(例如 checkAssetIsValid() 或类似方法)现在需要包级别公开,以便帮助器类可以调用它们,而之前作为内部类,它们可以是私有的。
更糟糕的是,我需要将服务实现类传递给辅助类构造函数,因为我不想在服务实现的接口中公开这些辅助方法,因为这会强制它们公开。这可能会产生一些单元测试/模拟问题。
更糟糕的是,我想做的任何同步都会通过一些外部便捷方法(例如轮询器更新期间的 lockDownAssets() )泄漏出去。之前,内部类可以访问私有锁。
因此,简而言之,将类打破会失去一些我喜欢的封装。但保留它们可能会导致一些大型 java 文件。我还没有找到处理这个问题的好方法。 C++ 有“朋友”的概念,我很少错过它,但在这种情况下实际上会有所帮助。
想法?
在字节码级别上,内部类只是普通的 Java 类。由于 Java 字节码验证器不允许访问私有成员,因此它会为您使用的每个私有字段生成合成访问器方法。此外,为了将内部类与其封闭实例链接起来,编译器将合成指针添加到外部“this”。
考虑到这一点,内部类只是一层语法糖。它们很方便,并且您列出了一些优点,所以我列出了您可能需要考虑的一些负面方面:
- Your inner class has a hidden dependency to the whole parent class, which obfuscates its inbound interface. If you extract it as package-private class you have a chance to improve your design and make it more maintainable. Initially it's more verbose, but often you'd find that:
- 您实际上希望共享一个值对象,而不是公开 10 个访问器。通常您会发现您并不真正需要对整个外部类的引用。这也适用于 IoC。
- 与其提供显式锁定的方法,不如将操作及其上下文封装在单独的类中(或将其移动到两个类之一 - 外部类或以前的内部类),从而更易于维护。
- 便捷方法属于包私有实用程序类。您可以使用 Java5 静态导入使它们显示为本地。
- 您的外部类可以绕过任何保护级别并直接访问内部类的私有成员。这本身并不是一件坏事,但它剥夺了表达设计的一种语言方式。
- 由于您的内部类正好嵌入一个外部类中,因此重用它的唯一方法就是对外部类进行子类化。另一种方法是传递对外部类实现的包私有接口的显式引用。这将允许您模拟外部类并更好地测试内部类。
- 虽然最近的调试器相当不错,但我之前在调试内部类时遇到过问题(条件断点范围混乱、不在断点处停止等)
- 私有类会使你的字节码膨胀。请参阅我的第一段 - 通常有一个 API 可供您使用并减少合成垃圾的数量。
附:我说的是非平凡的内部类(特别是那些不实现任何接口的内部类)。三行侦听器实现很好。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)