【问题标题】:How to make code modular?如何让代码模块化?
【发布时间】:2010-11-29 11:25:35
【问题描述】:

我有一些Java程序,现在我想知道它是否是模块化的,如果它是模块化的那么到什么程度,因为模块化永远不可能是二进制项,即0或1。 我如何确定特定代码在很大程度上是模块化的。我想知道如何让代码更加模块化?

【问题讨论】:

  • 如果代码是真正模块化的,那么每个组件都应该是一个黑盒子。知识组件彼此了解的越少,系统就越模块化。

标签: java module osgi modularity


【解决方案1】:

模块化的一些基准:

  1. 你有多少次rewriting similar code来完成一项特定的任务?
  2. 当您更改程序的某些部分时,您需要向 refactor your code 支付多少费用?
  3. 文件是否小而容易浏览?
  4. application modules 是否在需要时充分且独立地执行?
  5. 您的代码是否灾难性最小?当您仅删除一个函数或变量时,所有的地狱都会丢失吗? 重命名类时会出现 20 多个错误吗?(要检查这一点,您可以实现 堆栈机制 以跟踪应用程序中的所有跃点)
  6. 代码与自然语言使用的距离有多近?(即模块及其子组件代表更多真实世界的对象,而无需过多关注净源文件大小)。

有关更多想法,请查看this blurb about modularitysoftware quality 上的这个

至于你对让你的代码更加模块化的担忧,首先你应该问自己上面的问题,获得具体的答案,然后看看this

基本理念是将您的应用程序分解为尽可能小的代码片段,整齐地排列在大量易于理解和访问的目录布局中。

您的应用程序中的每个方法不得超过所需的最小处理量。将这些方法组合成越来越多的宏级方法应该会让您回到您的应用程序。

【讨论】:

  • 另一个基准可能是“删除标准”:如果您从程序中删除 X(包、类、方法、字段),会出现什么问题?如果有中断,它们离删除的项目有多“远”?如果损坏的项目距离很远,那么这意味着 X 的模块化程度较低。
  • (添加到上一条评论) - 当您删除某些内容时,您会立即公开它与程序其余部分的连接 - 所有连接到调用代码的地方。更多的模块化通常意味着更少的连接点,并且通常意味着连接点在范围内更加“本地化”(例如,在单个包内)。
  • 虽然它在重构部分和模块的独立测试中得到了照顾,但单独提及它仍然没有坏处!
  • 很遗憾,“检查一下”链接已损坏。
【解决方案2】:

重点是

  • 关注点分离
  • 凝聚力
  • 封装(通过接口通信)
  • 可替代性
  • 可重用性

此类模块系统的一个很好的例子是标准汽车零件,如盘式制动器和汽车音响。 在制造汽车时,您不想从头开始制造汽车音响。您宁愿购买它并插上电源。您也不希望制动系统影响汽车音响—— 或更糟糕的汽车音响影响制动系统。

要回答您的问题,“我如何确定特定代码在很大程度上是模块化的”,我们可以形成问题来测试模块化。 您能否轻松地用其他东西替换您的模块而不影响应用程序的其他部分?

XML 解析器可能是另一个例子。一旦你获得了 DOM 接口,你就真的不关心下面使用的是哪个 XML 解析器的实现(例如 Apache Xerces 或 JAXP)。

在 Java 中,另一个问题可能是:所有功能都可以通过interfaces 访问吗?接口几乎可以解决低耦合问题。

另外,你能用一句话描述系统中的每个模块吗?例如,汽车音响播放音乐和收音机。盘式制动器使车辆安全减速。


(这是我写给What is component driven development?的内容)

根据维基百科,基于组件的开发是Component-based software engineering (CBSE) 的别名。

[It]是软件的一个分支 工程,其优先级是 关注点分离 广泛的功能 在给定的软件中可用 系统。

这有点模糊,所以让我们看看更多细节。

单个组件是一个软件 包或模块 封装了一组相关的 函数(或数据)。

所有系统进程都放入 分开的组件,使所有的 每个内部的数据和函数 组件在语义上相关 (就像内容一样 类)。因为这个原则, 人们常说组件是 模块化内聚

所以,根据这个定义,一个组件可以是任何东西,只要它真正做好一件事并且只做一件事。

关于全系统 协调,组件通信 通过接口相互交流。 [...] 这一原则导致组件被称为封装

所以这听起来越来越像我们认为好的 API 或 SOA 应该有的样子。

provided 接口用棒棒糖表示,必需 接口用 UML 中附加到组件外边缘的打开套接字符号表示。

另一个重要的属性 组件是它们是 可替换,这样一个组件 可以被另一个替换(在 设计时或运行时),如果 初始组件的要求 (通过接口表示)得到满足 由后继组件。

可重用性很重要 高品质的特征 软件组件。一个软件 组件应该被设计和 实施以便可以重复使用 在许多不同的程序中。

可替换性和可重用性使组件成为组件。 那么这和面向对象编程有什么区别呢?

面向对象的思想 编程(OOP)是那个软件 应该按照一个写 实际或想象的心智模型 它代表的对象。 [...]

基于组件的软件工程, 相比之下,没有这样 假设,而是指出 软件应该通过胶合来开发 预制构件在一起很多 就像在电子领域或 力学。

【讨论】:

    【解决方案3】:

    嘿嘿,

    请参阅此处的“如何封装软件(第 1 部分)”:

    http://www.edmundkirwan.com/encap/overview/paper7.html

    问候,

    编。

    【讨论】:

      【解决方案4】:

      由于这已被标记为“osgi”,我可以提出一个与 OSGi 相关的观点。

      简短的回答是,可以通过小步骤从完全意大利面条式代码转变为模块化;不一定是大爆炸。例如,即使是意大利面条代码也依赖于某种肉酱日志库,所以从某种意义上说,它已经是模块化的,只是其中包含一个非常大的 Metball(对不起,模块)。

      诀窍是将大肉丸分成一个更小的块,然后是一个稍微小一点的肉丸,然后递归。也不必一口气完成。每次只需多削一点,直到没有东西可以去除。

      对于 OSGi,仍然可以将 uber-jar 放入包中。实际上,您可以在不更改位的情况下执行此操作;通过修改 Manifest.MF,或者将其包装在另一个 JAR 中并在清单中指定 Bundle-ClassPath: metaball.jar。

      如果做不到这一点,像 BND 这样的工具可以帮助生成您需要的正确数据,然后可以轻松地将其放入 OSGi 运行时。但要小心过度耦合的代码,以及与类加载器混在一起的东西——它们会让你大吃一惊。

      【讨论】:

        【解决方案5】:

        package-by-feature 的想法有助于使代码更加模块化。

        在网络上看到的许多示例首先将应用程序划分为层,而不是功能

        • 型号
        • 数据访问
        • 用户界面

        不过,使用与功能而非层一致的顶级包来划分应用程序似乎更好。

        这是一个使用按功能打包的网络应用程序的example。请注意顶级包的名称,它们读作应用程序中实际功能的列表。还要注意每个包如何包含与功能相关的所有项目 - 这些项目不会散布在所有地方;大多数时候,它们都在一个包/目录中。

        通常,删除此类应用程序中的功能可以在单个操作中实现 - 删除单个目录。

        【讨论】:

          【解决方案6】:

          要回答您关于如何使代码更加模块化的具体问题,有以下几种方法:

          • 模块化的最佳工具之一是发现代码重用。如果您发现您的代码在不止一次的地方执行相同(或非常相似)的事情,那么它是模块化的一个很好的候选者。

          • 确定哪些逻辑可以独立,从某种意义上说,其他逻辑可以使用它们而无需知道它们是如何构建的。这有点类似于您在 OO 设计中所做的,尽管模块/组件不一定需要与 OO 中的建模对象相对应。

          【讨论】:

            【解决方案7】:

            您可以使用CAP等代码分析工具来分析类型和包之间的依赖关系。它们将帮助您查找和删除任何循环依赖项,这在尝试开发模块化代码时通常是一个问题。 如果没有循环依赖,你可以开始将你的代码分离成独立的 jars。

            一般来说,如果可以的话,最好为接口编写代码,这通常意味着您的代码可以更容易地被重构和/或在不同的上下文中使用。

            Spring 等依赖注入框架也可以帮助您实现设计的模块化。由于类型是通过一些外部配置过程注入其依赖关系的,因此它们不需要直接依赖于实现。

            【讨论】:

              【解决方案8】:

              模块化与开发代码的人有关。但我认为普遍的共识是模块化代码是具有可以轻松交换的部分代码,而无需更改大部分原始代码。

              恕我直言,如果您有 3 个模块 A B 和 C,并且您想完全更改或替换模块 C,如果这是一项简单的任务,那么您就有了模块化代码。

              【讨论】:

                【解决方案9】:

                正如你所说的模块化不是一个二元的东西,所以它取决于你的相对定义。

                我会说:你可以在任何需要执行该功能的程序中使用给定的方法吗?它是“黑匣子”吗?你不需要知道它在幕后做什么?如果答案是否定的,即该方法只能在该程序中正常工作,那么它就不是真正的模块化。

                【讨论】:

                  【解决方案10】:

                  假设我理解您的问题,您想知道是什么使代码模块化,因为代码模块显然需要彼此之间存在一定的依赖关系才能工作。这是我的答案:

                  如果您可以将系统分解为模块,并且可以单独测试这些模块,那么这很好地表明了系统是模块化的。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-11-15
                    • 1970-01-01
                    • 2011-12-29
                    • 2014-05-23
                    • 1970-01-01
                    • 2021-02-05
                    相关资源
                    最近更新 更多