idea如何把包变为模块_让我们将包变成模块系统!

idea如何把包变为模块

使用构建系统将许多项目分为模块/子项目( Maven , Gradle , SBT …); 编写模块化代码通常是一件好事。 将代码分为构建模块主要用于:

  • 隔离代码部分(减少耦合)
  • api / impl拆分
  • 仅将第三方依赖项添加到代码的特定部分
  • 具有相似功能的代码分组
  • 静态检查一个模块中的代码仅使用其依赖模块(模块间依赖)中的代码

尽管有些人可能说它对于单独的编译也很有用,但我认为这并不重要(考虑一个项目时)。 如今,构建工具非常聪明,可以找出需要重新编译的内容。

构建模块问题

我认为这种方法存在一些问题。 首先,很难确定何时某个功能“足够大”以将其转换为构建模块。 几门课就够了吗? 还是您需要更多? 严格来说,每个模块是否应该只有一种功能? 但这会导致模块爆炸。 等等。 至少在我参与的项目中,这是讨论的共同主题,即构建模块的粒度应如何粗略。

其次,构建模块非常“繁重”。 我想Maven最糟糕,您需要大量的xml来创建一个带有大量样板文件的模块(例如,重复的组ID,版本号,父级定义); SBT和Gradle更好,但仍然是一项巨大的努力。 需要创建一个单独的目录,整个目录结构( src/main/...src/test/... ),更新构建配置等。总的来说,这很麻烦。

然后,当我们将漂亮的模块分开时,经常会发现,为了使它们中的两个相互协作,我们需要一个“通用”部分。 然后,我们要么以一个肿的foo-common模块结束,该模块包含不相关类的负载,要么以多个小型foo-foomodule-common模块结束; 第二种解决方案当然没问题,只是浪费时间进行设置。

最后,构建模块是您还必须命名的其他内容。 软件包名称和类名称很可能已经反映了代码的作用,现在还需要在构建模块名称中重复(违反DRY)。

总而言之,我认为创建构建模块非常困难且耗时。 程序员是懒惰的(当然,这是一件好事),这导致设计不像它们可能的那么干净。 是时候改变它了:)

(另请参见我之前有关模块的博客 。)

配套

Java,Scala和Groovy已经有一个用于对代码进行分组的系统:程序包。 但是,当前包仅是字符串标识符。 除了一些非常有限的可见性选项(在Java中为package-private,在Scala中为package-scoping)之外,软件包没有语义。 因此,我们有几个级别的分组代码:

  1. 项目
  2. 构建模块

如果我们将2.和3.合并在一起会怎样? 为什么不应该使用软件包来创建模块?

包作为模块?

让我们来看看将包扩展为模块会怎样。 显然,我们需要做的第一件事是将一些元数据与每个模块相关联。 已经有一些机制(例如,通过package-info.java上的注释),或者这可能是Scala中软件包对象的扩展-可以混入某些特征,或覆盖val

什么样的元数据? 当然,我们不想将整个构建定义移到软件包中。 但是让我们分开关注 –构建定义应该定义如何构建项目,而不是模块依赖项。 然后,在模块的元数据中定义的第一件事就是对第三方库的依赖。 这样的定义可能只是符号,它将被绑定到构建定义中的具体版本。

例如,我们将指定包“ foo.bar.dao ”取决于“ jpa ”库。 然后,构建定义将包含从“ jpa ”到Maven工件列表的映射(例如hibernate-core,hibernate-entitymanager等)。 而且,如果这种依赖关系可以传递到子包,则可能最有意义。 因此,定义全局库将意味着增加对根包的依赖。

附带说明一下,通过扩展Scala的包对象,甚至可以将其设置为类型安全的。 包对象可以实现特征,其中要覆盖的值之一可以是第三方依赖项符号的列表。 符号本身可以包含在根包中定义的Enumeration中; 这可以使诸如“根据jpa查找所有模块”之类的事情在IDE中进行简单的用法搜索。

第二步是也使用此机制定义模块间依赖关系。 在包的元数据中,可以定义其他包的列表,从中可以看到代码。 这遵循当前构建模块的使用方式:每个构建模块均包含可访问的项目模块的列表。 (另一个Scala旁注:由于包对象将实现特征,这意味着定义具有给定类型的对象列表。)

更进一步,我们可以指定apiimpl类型包。 默认情况下,可以从其他软件包访问Api型的。 另一方面,如果不将Impl类型的程序包明确指定为依赖项,则无法访问它们。

在实践中看起来如何? Scala中的一个非常粗糙的草图:

package foo.user// Even without definition, each package has an implicit package object 
// implementing a PackageModule trait ...
package object dao { // ... which is used here. The type of the val below is // List[PackageModule].override val moduleDependsOn = List(foo.security, foo.user.model) override val moduleType = ModuleType.API// FooLibs enum is defined in a top-level package or the build systemoverride val moduleLibraries = List(FooLibs.JPA) 
}


重构

重构是日常活动; 但是,重构模块通常是一项艰巨的任务,有时只能使用一次。 应该是这样吗? 如果将程序包扩展到模块,则重构模块将与四处移动和重命名程序包相同,另外还需要更新元数据。 这将比现在容易得多,我认为这将导致更好的总体设计。

建立系统

上面的内容显然意味着构建系统需要做更多的工作–很难弄清模块列表,构建顺序,要创建的工件列表等(顺便说一句,如果要为一个程序包创建一个单独的jar,可以也是元数据的一部分)。 此外,还需要进行一些验证-循环依赖关系,或试图以错误的方式限制可见性。

但是后来,人们做了比这更复杂的软件

拼图?

您可能会说,这与项目Jigsaw重叠,后者将在Java 9中(或不是)中出现。 但是,我认为Jigsaw的目标范围不同:项目级别的模块。 因此,一个拼图模块将是您的整个项目,而您将拥有多个(数十个)程序包模块。

名称“模块”在这里是重载的,也许名称“迷你模块”会更好,或者适度地“正确地打包”。

底线

我认为,当前定义构建模块的方法太过困难且受限制。 另一方面,将包装提升至模块将非常轻巧。 定义一个新模块与创建一个新程序包相同–简单得多。 第三方库只能在需要的地方添加。 少说一件事。 每个项目只有一棵源树。

同样,这种方法可以根据项目需求进行扩展和调整。 无需花费太多精力就可以定义细粒度模块或粗粒度模块。 甚至更好的是,为什么不创建两个模块呢?模块可以嵌套并在另一个模块之上构建。

现在…唯一的问题是实现并添加IDE支持;)

参考: 让我们将包变成模块系统! 来自我们的JCG合作伙伴 Adam Warski, 网址为Adam Warski博客。

翻译自: https://www.javacodegeeks.com/2012/11/lets-turn-packages-into-a-module-system.html

idea如何把包变为模块

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351804.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS2017无法启动

新安装了VS2017,安装没问题,但是总出现启动时没反应的状况,鼠标双击后转圈,然后就没然后了。。 解决办法: 第一步: 开始-->所有程序-->Microsoft Visual Studio 2017文件夹-->VisualStudio Tool…

gm怎么刷东西 rust_Rust语言:解引用详述,搞不明白这个概念,趁早放弃Rust

Rust是内存安全的,对新手来说,最大的困难是可恶的编译器,在其他语言上面叱咤风云,偏偏被Rust搞到崩溃。所以,大家都戏谑道,Rust是面向编译器编程。和编译器做斗争的过程中,遇到最多的是&#xf…

VS2010中使用gtest简单案例

1、下载googletest代码 https://github.com/google/googletest 2、解压并进入找到msvc文件夹 googletest-master\googletest-master\googletest\msvc 3、打开gtest.sln文件 4、编译gtest和gtest_main工程,生成gtestd.lib和gtest_maind.lib,将这两个静…

记录一次Oracle注入绕waf

这个注入挺特殊的,是ip头注入。我们进行简单的探测: 首先正常发起一次请求,我们发现content-type是76 探测注入我习惯性的一个单引号: 一个单引号我发现长度还是76 我开始尝试单引号,双引号一起: 我失败了长度还是76 一般sql注入输入单引号一…

生成字节码

在这篇文章中,我们将看到如何为我们的语言生成字节码。 到目前为止,我们已经看到了如何构建一种语言来表达我们想要的东西,如何验证该语言,如何为该语言构建编辑器,但实际上我们仍然无法运行代码。 是时候解决这个问题…

Java迭代器contains的问题

功能:ArrayList去除集合中字符串的重复值(字符串的内容相同),思路:创建新集合方式。 第一种编译运行没问题,第二种写法出错,原因是不可以两次使用it.next()。 错误提示:Exception in thread "main&q…

ad如何镜像器件_使用 Dockerfile 制作镜像

前面几篇文章已经给大家介绍了 Docker 的基本概念,相信大家也会使用 Docker 运行自己想要的容器了。但是只有学会制作镜像,才能将 Docker 应用到我们的项目中去。下面我们就来学习如何使用 Dockerfile 来制作镜像。Dockerfile 是一个文本文件&#xff0c…

centos7.5部署ELk

第1章 环境规划 1.1 ELK介绍 ELK是ElasticSerach、Logstash、Kibana三款产品名称的首字母集合,用于日志的搜集和搜索。 Elasticsearch:是一个开源分布式搜索引擎,提供搜集、分析、存储三大功能,特点是分布式、零配置、自动发…

使用Google Test的一个简单例子

0. 引子 本例是从 gtest-1.5.0 自带的 sample 中的 sample1 改写而来&#xff0c;笔者只添加了一个求 n 的阶层的函数&#xff0c;如下。 void Factorial(int n, int & result ) { result 1; for (int i 1; i < n; i) result * i; } 目的是想测试像这样将返回值放在参…

Java静态方法与非静态方法的泛型

Java中&#xff0c;非静态方法可以使用类的泛型&#xff0c;也可以定义自己的泛型&#xff1b;静态方法由于随着类的加载而加载&#xff0c;不能访问类的泛型&#xff08;因为在创建对象的时候才确定&#xff09;&#xff0c;因此必须定义自己的泛型类型。 详细请参考&#xf…

Android Studio 日志工具

在项目中提供5个方法打印日志 Log.v() 最常见的日志信息 Log.d() 调试信息 Log.i() 用于打印用户操作行为 Log.w()警告潜在风险 Log.e()报错信息 TAG 填入类名就好 msg:要打印的信息 也可以对信息进行过滤 点他弹出自定义的日志过滤器 转载于:https://www.cnblogs.com/feizianq…

jpa加密_使用JPA侦听器的数据库加密

jpa加密最近&#xff0c;我不得不将数据库加密添加到一些字段中&#xff0c;并且发现了很多不好的建议。 建筑问题 最大的问题是建筑。 如果持久性管理器静静地处理您的加密&#xff0c;那么根据定义&#xff0c;您的体系结构将在持久性和安全性设计之间要求紧密而不必要的绑…

同一进程中的线程究竟共享哪些资源

线程共享的环境包括&#xff1a;进程代码段、进程的公有数据(利用这些共享的数据&#xff0c;线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这许多共性的同时&#xff0c;还拥有自己的个性。有了这些…

物联lot是什么意思_什么是物联网,物联网(lOT)简介

什么是物联网物联网(The Internet of Things&#xff0c;简称IOT)是指通过各种信息传感器、射频识别技术、全球定位系统、红外线感应器、激光扫描器等各种装置与技术&#xff0c;实时采集任何需要监控、 连接、互动的物体或过程&#xff0c;采集其声、光、热、电、力学、化 学、…

Python 位操作运算符

&按位与运算符&#xff1a;参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0(a & b) 输出结果 12 &#xff0c;二进制解释&#xff1a; 0000 1100|按位或运算符&#xff1a;只要对应的二个二进位有一个为1时&#xff0c;结果位就为1。(a | b) 输出结果 6…

JavaOne 2016后续活动

我很高兴今年参加了JavaOne&#xff0c;我可以用一个词概括一下这一经验&#xff1a;Brilliant。 对于我来说&#xff0c;今年与往年相比有很大不同&#xff0c;因为我在周日有一个演讲要共同演讲&#xff0c;而我剩下的一周时间都可以参加会议。 因此&#xff0c;我了解到在Ja…

python对初学者的看法_python学习之道(1)——新手小白对print()函数的理解,Python,之路,一,浅谈...

Python学习之路(一) ——浅谈新手小白对print()函数的理解写在前面笔者目前为在校大四学生(某末流211)&#xff0c;大学生活即将画上终点&#xff0c;然而却还没有真正精通一门语言&#xff0c;很是惭愧。在大学期间参加了各种文体活动&#xff0c;获得了很多次演讲比赛的奖项&…

理解Windows内核模式与用户模式

&#xfeff;&#xfeff;1、基础 运行 Windows 的计算机中的处理器有两个不同模式&#xff1a;“用户模式”和“内核模式”。根据处理器上运行的代码的类型&#xff0c;处理器在两个模式之间切换。应用程序在用户模式下运行&#xff0c;核心操作系统组件在内核模式下运行。多个…

判断使用设备是PC还是phone

<script type"text/javascript"> //如果是手机设备&#xff0c;则.. if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {window.location.href "http://www."; } </script><style type"text/css"> me…

求1+2+3+...+n

题目描述 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C&#xff09;。 1、根据基本公式展开&#xff0c;利用java的幂函数代替乘法&#xff0c;利用位移运算代替除法 public class Solution {pub…