让我们将包变成模块系统!

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

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

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

构建模块问题

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

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

然后,当我们经常将漂亮的模块分开时,事实证明,要使其中两个模块相互协作,我们需要一个“通用”部分。 然后,我们要么以一个blo肿的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博客的Blog。

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

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

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

相关文章

R语言日期的表示和运算(详细总结)

1、取出当前日期 Sys.Date() [1] "2014-10-29" date() #注意:这种方法返回的是字符串类型 [1] "Wed Oct 29 20:36:07 2014" 2、在R中日期实际是double类型,是从1970年1月1日以来的天数 typeof(Sys.Date()) [1] "double" …

html高度塌陷问题解决

高度塌陷的问题: 当开启元素的BFC以后,元素将会有如下的特性 1 父元素的垂直外边距不会和子元素重叠 开启BFC的元素不会被浮动元素所覆盖 开启BFC的元素可以包含浮动的子元素 如何开启元素的BFC 设置元素浮动 设置元素绝对定位 …

java空格键_Java KeyPressed-如果其他键也太旧,则无法检测是否按下了空格键

如标题所示,在我的Java游戏中,无法检测是否同时按下空格键和其他键。例如,空格键是射击键,而箭头键则使玩家移动。如果我按下向上箭头键,向左箭头键和空格键,那么它应该向左上方发射子弹。但是,…

How to fix the bug “Expected required, optional, or repeated.”?

参考:https://github.com/tensorflow/models/issues/1834 You need to download protoc version 3.3 (already compiled). Used protoc inside bin directory to run this command like this:tensorflow$ mkdir protoc_3.3tensorflow$ cd protoc_3.3tensorflow/prot…

立面设计模式–设计观点

在上一篇文章中,我们描述了适配器设计模式 。 在今天的文章中,我们将展示另一种类似的“四结构帮派”模式 。 顾名思义,结构模式用于从许多不同的对象形成更大的对象结构。 外观模式就是这样一种模式,它为系统内的一组接口提供了简…

Java第三次作业 1502 马 帅

《Java技术》第三次作业 (一)学习总结 1.书中对面向对象封装性的定义为:指把对象的属性和行为看成一个密不可分的整体,把不需要让外界知道的信息隐蔽起来。简单来说,就是定义的一些对象,只有在本类中才可以…

sass运算

sass具有运算的特性,可以对数值型的Value(如:数字、颜色、变量等)进行加减乘除四则运算。 请注意运算符前后请留一个空格,不然会出错。 scss.style css.style 本文转载于:猿2048https://www.mk2048.com/blog/blog.php?idiij12j&titles…

163 coremail_Icoremail企业邮箱

高速稳定iCoremail企业邮箱于国内外多个网络运营商的主干网数据中心放置邮件服务器,同时采用我司自主研发的Coremail电子邮件系统,从多方面保障了用户的流畅体验。安全可靠iCoremail企业邮箱使用欧洲最大的反病毒安全提供商的Sophos反病毒系列产品&#…

jquery-基础事件[下]

<script>$(function () {mouseover mouseout mouseenter mouseleave的区别$(div).mouseover(function () {$(this).css(background, red);}).mouseout(function () {$(this).css(background, green);});$(div).mouseenter(function () {$(this).css(background, red);}).…

JavaOne 2012:NetBeans.Next –未来路线图

我从Continental Ballroom 4和一个NetBeans主题&#xff08; 项目Easel &#xff09;到Continental Ballroom 5&#xff0c;走了必要的几个步骤&#xff0c;以查看另一个面向NetBeans的演示文稿&#xff1a;“ NetBeans.Next –未来路线图”。 Ashwin Rao发起了“羽毛之鸟”&am…

LeetCode day30

LeetCode day30 害&#xff0c;昨天和今天在搞数据结构的报告&#xff0c;后面应该也会把哈夫曼的大作业写上来。 今天认识认识贪心算法。(&#xff61;&#xff65;∀&#xff65;)&#xff89; 2697. 字典序最小回文串 给你一个由 小写英文字母 组成的字符串 s &#xff0c;…

html注册表

这是第一次使用html写一个简单的注册表&#xff08;有不对的地方希望大家可以帮我指出来谢谢?&#xff09; <!DOCTYPE html><html><head> <title>木木音乐网第一次注册表</title></head><body><h2>使用手机号码注册</…

C#复习正则表达式

由于前段时间为了写工具学的太J8粗糙 加上最近一段时间太浮躁 所以静下心来复习 一遍以前学的很弱的一些地方1 委托 public delegate double weituo(double a, double b);public static double test1(double a,double b){return a * b;}public static double test2(double a,…

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

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

Java是先难后易吗_在解决问题的时候,是先难后易还是先易后难?

有家长问&#xff0c;孩子一旦听到不同声音&#xff0c;就沮丧&#xff0c;一旦有难的事情&#xff0c;就逃避&#xff0c;怎么办&#xff1f;回答这个问题之前&#xff0c;我们问一个问题“你给孩子玩穿纽扣游戏&#xff0c;是一开始给孩子玩容易穿的纽扣好呢&#xff1f;还是…

在vue中安装使用vux

最近因为的工作的原因在弄vue&#xff0c;从后端弄到前端之前一直用js&#xff0c;现在第一次接触vue感觉还挺有意思的&#xff0c;就是自己太菜了&#xff0c;这个脑子呀。。。。不太够用。。。。。页面设计用了一个叫vux的东西&#xff0c;vux可以提供一些组件&#xff0c;用…

form表单 获取与赋值

form表单中使用频繁的组件: 文本框、单选框、多选框、下拉框、文本域form通过getValues()获取表单中所有name的值 通过setValues({key:values})给对应的name值进行赋值&#xff0c;其中key对应的name值 在给单选框和多选框赋值时&#xff0c;有几个疑惑的地方&#xff1a;  …

Zabbix全方位告警接入-电话/微信/短信都支持

http://www.cnblogs.com/baidu-gaojing/p/5128035.html 百度告警平台地址&#xff1a; http://gaojing.baidu.com 联系我们&#xff1a; 邮箱&#xff1a;gaojingbaidu.com 电话&#xff1a;13924600771 QQ群&#xff1a;183806029 对于使用zabbix的用户&#xff0c;要接入百度…

Spring MVC定制用户登录注销实现示例

这篇文章描述了如何实现对Spring MVC Web应用程序的自定义用户访问&#xff08;登录注销&#xff09;。 作为前提&#xff0c;建议读者阅读这篇文章 &#xff0c;其中介绍了一些Spring Security概念。 该代码示例可从Spring-MVC-Login-Logout目录中的Github获得。 它从带有注释…

HTML5与CSS3权威指南笔记案例1

第1章 <!DOCTYPE html> <meta charset "UTF-8"> <title> Search </title> <form> <p><label>Search&#xff1a;<input name"search" autofocus></label> </p> </form> <!DOCTYPE&…