大型内部类和私有变量

2024-01-07

我多次遇到的一件事是服务类(如 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(使用前将#替换为@)

    大型内部类和私有变量 的相关文章

    • Java - 因内存不足错误而关闭

      关于如何最好地处理这个问题 我听到了非常矛盾的事情 并且陷入了以下困境 OOME 会导致一个线程崩溃 但不会导致整个应用程序崩溃 我需要关闭整个应用程序 但不能 因为线程没有剩余内存 我一直认为最佳实践是让它们离开 这样 JVM 就会死掉
    • 如何使用Spring WebClient进行同步调用?

      Spring Framework in 休息模板 https docs spring io spring framework docs current javadoc api org springframework web client R
    • 使用 JDBC 获取 Oracle 11g 的最后插入 ID

      我是使用 Oracle 的新手 所以我将放弃之前已经回答过的内容这个问题 https stackoverflow com questions 3131064 get id of last inserted record in oracle
    • “java.io.IOException:连接超时”和“SocketTimeoutException:读取超时”之间有什么区别

      如果我设置一个套接字 SoTimeout 并从中读取 当读取时间超过超时限制时 我会收到 SocketTimeoutException 读取超时 这是我的例子中的堆栈 java net SocketTimeoutException Read
    • 带有 Android 支持库 v7 的 Maven Android 插件

      我使用 maven android plugin 构建我的 android 应用程序 它依赖于 android 支持库 v4 和 v7 由于我没有找到如何从developer android com下载整个sdk 因此我无法使用maven
    • 使用 WebDriver 单击新打开的选项卡中的链接

      有人可以在这种情况下帮助我吗 场景是 有一个网页 我仅在新选项卡中打开所有指定的链接 现在我尝试单击新打开的选项卡中的任何一个链接 在下面尝试过 但它仅单击主 第一个选项卡中的一个链接 而不是在新选项卡中 new Actions drive
    • 当路径的点超出视野时,Android Canvas 不会绘制路径

      我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
    • 如何使用 JAVA 代码以编程方式捕获线程转储?

      我想通过 java 代码生成线程转储 我尝试使用 ThreadMXBean 为此 但我没有以正确的格式获得线程转储 因为我们正在使用jstack命令 请任何人提供一些帮助 他们是否有其他方式获取线程转储 使用任何其他 API 我想要的线程转
    • HAProxy SSL终止+客户端证书验证+curl/java客户端

      我希望使用我自己的自签名证书在 HAProxy 上进行 SSL 终止 并使用我创建的客户端证书验证客户端访问 我通过以下方式创建服务器 也是 CA 证书 openssl genrsa out ca key 1024 openssl req
    • Android 中 localTime 和 localDate 的替代类有哪些? [复制]

      这个问题在这里已经有答案了 我想使用从 android API 获得的长值 该值将日期返回为长值 表示为自纪元以来的毫秒数 我需要使用像 isBefore plusDays isAfter 这样的方法 Cursor managedCurso
    • 为什么Iterator接口没有add方法

      In IteratorSun 添加了remove 方法来删 除集合中最后访问的元素 为什么没有add方法来向集合中添加新元素 它可能对集合或迭代器产生什么样的副作用 好的 我们开始吧 设计常见问题解答中明确给出了答案 为什么不提供 Iter
    • Android蓝牙java.io.IOException:bt套接字已关闭,读取返回:-1

      我正在尝试编写一个代码 仅连接到运行 Android 5 0 KitKat 的设备上的 目前 唯一配对的设备 无论我尝试了多少方法 我仍然会收到此错误 这是我尝试过的最后一个代码 它似乎完成了我看到人们报告为成功的所有事情 有人能指出我做错
    • 如何使用正则表达式验证 1-99 范围?

      我需要验证一些用户输入 以确保输入的数字在 1 99 范围内 含 这些必须是整数 Integer 值 允许前面加 0 但可选 有效值 1 01 10 99 09 无效值 0 007 100 10 5 010 到目前为止 我已经制定了以下正则
    • 如何通过注解用try-catch包装方法?

      如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
    • 在 Clojure 中解压缩 zlib 流

      我有一个二进制文件 其内容由zlib compress在Python上 有没有一种简单的方法可以在Clojure中打开和解压缩它 import zlib import json with open data json zlib wb as
    • Java - 从 XML 文件读取注释

      我必须从 XML 文件中提取注释 我找不到使用 JDOM 或其他东西来让它们使用的方法 目前我使用 Regex 和 FileReader 但我不认为这是正确的方法 您可以使用 JDOM 之类的东西从 XML 文件中获取注释吗 或者它仅限于元
    • Lombok @Builder 不创建不可变对象?

      在很多网站上 我看到 lombok Builder 可以用来创建不可变的对象 https www baeldung com lombok builder singular https www baeldung com lombok buil
    • 使用Java绘制维恩图

      我正在尝试根据给定的布尔方程绘制维恩图 例如 a AND b AND c我想在 Android 手机上执行此操作 因此我需要找到一种使用 Java 来执行此操作的方法 我找到了一个完美的小部件 它可以完成我在这方面寻找的一切布尔代数计算器
    • 如何处理 StaleElementReferenceException

      我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
    • 将对象从手机共享到 Android Wear

      我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向

    随机推荐

    • 如何接入Kubernetes部署

      我已经创建了 Docker 映像 并部署在具有最少数量机器的 k8s 集群中 设置了一台主机和一台工作机 两台机器都已启动并运行 并使用相同的 VLAN 网络相互通信 请查找以下 Pod 和部署服务以及所描述的状态 root jenkins
    • 如何配置 protobuf-net 的 RuntimeModel.Default 以支持序列化/反序列化 SessionSecurityToken?

      BinaryFormatter 能够简单地处理序列化 private byte TokenToBytes SessionSecurityToken token if token null return null using var memo
    • XML 格式中的换行符?

      在 XML 中编辑字符串时 我需要添加换行符 我想问一下 为 android 编程时 正确的形式是什么 因为 br 有效 但 ECLIPSE 将该区域标记为有问题 如果我查看建议 Eclipse 会告诉我我应该添加一个结束标签 如果我添加换
    • Blazor 作用域 CSS 未在 Azure Pipelines 上构建

      我正在开发一个使用作用域 CSS 的 Blazor 应用程序 但是当我尝试使用 Azure Pipelines 构建它时 不会生成作用域 CSS 文件 我在一台可以通过 RDP 访问的本地计算机上构建 我看到wwwroot assembly
    • 从 mach_timebase_info() 创建结构体

      在 C 中创建时基信息结构很容易 但在 Swift 中 以下内容在 Playground 中不起作用 let timebaseInfo mach timebase info data t mach timebase info timebas
    • 使用 pandas 和 scipy 绘制树状图

      我希望使用相关性生成树状图pandas and scipy 我使用数据集 作为DataFrame 由返回组成 其大小为n x m where n是日期的数量 m公司数量 然后我只需运行脚本 import pandas as pd impor
    • 如何让 ediff + hg 在 emacs 23.2 for mac 中工作?

      我使用 emacs 二进制文件http emacsformacosx com http emacsformacosx com 当我在 Mercurial 源目录中编辑文件并运行 ediff revision 时 我得到 File the f
    • 错误:预期未定义为 GraphQL 模式

      我收到一条错误 内容为 错误 预期未定义为 GraphQL 架构 请检查一下这是什么问题 当我移动到 localhost 3000 graphiql 时 它显示上述错误 也许我犯了一些错误 请任何人检查并帮助我 如果可能的话 我的服务器 j
    • 人脸识别-Python

      我正在尝试通过以下方式进行人脸识别主成分分析 PCA 使用Python 现在我能够获得训练图像之间的最小欧几里德距离images和输入图像input image 这是我的代码 import os from PIL import Image
    • 获取正在激活的选项卡(div)的ID

      我正在使用 jquery 1 9 和 jquery UI 1 10 我希望能够在单击选项卡时获取选项卡 ID 例如 如果我单击名为 Second 的选项卡 我想获得 tabs 2 响应 到目前为止我已经完成了以下代码
    • 我是否应该同步监听器通知?

      我总是很犹豫是否要把我的锁公开 公开 我总是尝试将锁限制在我的实现范围内 我相信 不这样做就会导致僵局 我有以下课程 class SomeClass protected ArrayList
    • 用于相交列列表的一致 ColumnTransformer

      我想用sklearn compose ColumnTransformer对于相交的列列表 一致 不是并行的 因此 第二个变换器应该仅在第一个变换器之后执行 log transformer p FunctionTransformer lamb
    • Gitlab CI:仅在工件存在时运行作业

      我有 monorepo 我想根据已更改的目录内容运行子管道 在工作中prepare config我检查最新更改在哪里 我创建子配置 yml 并在下一阶段的工作中run child我从 运行子管道 问题是 如果model gitlab ci
    • 如何从 .net 中的 WSDL 文件生成客户端?

      我正在尝试从 WSDL 文件生成客户端 而不使用 Visual Studio 本身 并且不知道最好的起点是什么 客户需要使用相同的文件并为 PHP 应用程序生成客户端 我想通过自己创建客户端 在工作室之外 来证明 WSDL 是有效的 svc
    • 检测哪张SIM卡收到消息

      我正在尝试检测哪张 SIM 卡已在双 SIM 卡或三卡支持手机上的 BroadcastReceiver 中接收到传入消息 笔记 所有 SIM 卡都有相同的 SMSC 似乎信息可能位于带有密钥的 Intent extra 中 simSlot
    • 更改函数体内函数的属性?

      我正在尝试创建一个函数来记录它被调用的次数 并且我希望信息保留在函数本身内部 我尝试创建一个包装器 如下所示 def keep count f f count 0 functools wraps f def wrapped f args k
    • 将 SQL 查询读入 Dask DataFrame

      我正在尝试创建一个函数 该函数将 SQL SELECT 查询作为参数 并使用 dask 将其结果读入 dask DataFramedask read sql query功能 我是 dask 和 SQLAlchemy 的新手 我首先尝试了这个
    • Angular Elements - 外部库的 CSS

      我希望将 Angular Elements 与外部库 Kendo UI 一起使用 我设法创建一个组件并将其添加到我的应用程序中 问题是 Kendo 的 CSS 搞乱了我所有的应用程序样式 关于如何封装 CSS 以仅应用于组件而不是 泄漏 到
    • 尝试运行 OSGi 调试目标时支持“平台不受支持”

      我正在尝试运行 IntelliJ Idea 的一个小型 OSGi 项目 我已经在 Idea 的 OSGi 配置部分添加了 Equinox 容器 然后我将 OSGi 方面添加到项目中 到目前为止一切看起来都很好 然而 一旦我尝试运行该项目 我
    • 大型内部类和私有变量

      我多次遇到的一件事是服务类 如 JBoss 服务 由于助手内部类而变得过大 我还没有找到一个好的方法来打破课堂 这些助手通常是线程 这是一个例子 Asset service keeps track of the metadata about