/** 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. } } }
所以,如果我有几个帮助者,而且他们都很复杂,那么整体类文件可以变得非常大.我喜欢内部类,因为它清楚了这些类是由服务完全拥有,并且只存在来帮助这个服务.我已经尝试打破类,并将父级服务作为参考传递,这种工作主要是工作,但我不喜欢的是:
>我最终暴露了包级别的访问器,所以分解的类可以获得变量,而在我没有暴露setter之前,因为内部类有直接访问.
>另外,事情有点更加冗长,因为我不断调用访问器而不是基础变量.一个小小的,被授予.
>便利方法(例如checkAssetIsValid()或某些)需要打包级别的暴露,所以帮助类可以调用它们,如前所述,内部类可以是私有的.
>更糟糕的是,我需要将服务实现类传递给辅助类构造函数,因为我不想在服务实现的接口中公开这些helpers方法,因为这迫使它们被公开.这可能会产生一些单元测试/嘲笑问题.
更糟糕的是,我想做的任何同步通过一些外部的便利方法泄露出来(例如在轮询器更新期间的lockDownAssets()).之前,内部类可以访问私钥.
所以简而言之,打破这些课程会失去一些我喜欢的封装.但是让他们进入可能会导致一些大的java文件.我还没有找到一个很好的办法来处理这个问题. C有我很少错过的“朋友”的概念,但在这种情况下实际上是有帮助的.
思考?
解决方法
考虑到这一点,内部类只是一层语法糖.他们很方便,你列出了一些好点,所以我列出一些你可能想考虑的消极方面:
>您的内部类对整个父类具有隐藏的依赖关系,从而使其入站接口模糊.如果您将其解压缩为package-private类,则有机会改进您的设计并使其更易于维护.最初它更冗长,但是经常会发现:
>而不是暴露10个访问器,你实际上想要共享一个值对象.通常你会发现你真的不需要引用整个外部类.这也适用于IoC.
>而不是提供显式锁定的方法,将操作与其上下文封装在单独的类(或将其移动到两个类之一 – outer或formerly-inner)中更为可维护.
>便利方法属于包私有实用程序类.您可以使用Java5静态导入使其显示为本地.
>您的外部课堂可以绕过任何保护级别,直接访问内部课程的私人成员.这本身并不坏,但它消除了表达您的设计的语言手段之一.
>因为你的内部类被嵌入到一个外部类中,所以重用它的唯一方法是对外部类进行子类化.另一种方法是将显式引用传递给外部类实现的包私有接口.这将允许你嘲笑外部,并更好地测试内部类.
>虽然最近的调试器很好,我在调试内部类之前遇到过问题(有条件的断点范围混乱,不能在断点处停止等等)
私人课程会膨胀你的字节码.看到我的第一个段落 – 通常有一个API可以使用和减少合成的数量.
附:我在谈论不平凡的内部类(特别是没有实现任何接口的内部类).三线听众实现是好的.