IntelliJ IDEA内部设计

IntelliJ IDEA的第一版于2001年1月发布,当时它是第一个集成了高级代码导航和代码重构功能的Java IDE之一。

2009年,JetBrains开源了其社区版本 。 从那时起,创建了许多基于它的IDE,例如Google的Android Studio。

让我们使用JArchitect进入Intellij IDEA的社区版本,并发现一些内部设计选择。

1.模块化

Intellij IDEA使用许多项目进行了模块化。 主要的是“想法”。 实用程序类在“ util”项目中实现,“ openapi” jar包含开发Intellij IDEA插件所需的类型。

这是Intellij IDEA项目的列表,以及有关其类型的一些统计信息:

image001

每个项目都包含许多软件包以对其代码库进行模块化,并且采用了按功能打包的方法。

逐功能包使用程序包来反映功能集。 它将与单个功能(仅该功能)相关的所有项目放置在单个目录/程序包中。 这导致包装具有高内聚性和高模块化性,并且包装之间的耦合最小。 紧密协作的项目彼此相邻放置。

例如,这是来自idea项目的一些软件包,这些软件包显示了按功能分组的类型。

image002

2. Intellij IDEA开发人员广泛使用GoF设计模式

设计模式是一种软件工程概念,描述了针对软件设计中常见问题的重复解决方案。 GoF模式是最受欢迎的模式。

Intellij IDEA开发人员广泛使用GOF模式。 这是源代码中使用的一些方法。

2.1工厂

使用工厂来隔离实例化逻辑并增强内聚力很有趣。 这是源代码中定义的工厂列表:

image003

实施了许多工厂; 这里有一些是从TextEditorHighlihtingPassFactory继承的。

image004

2.2转接器

适配器模式充当两个不兼容接口之间的桥梁。 这种设计模式属于结构模式,因为该模式结合了两个独立接口的功能。

Intellij IDEA源代码中实现了许多适配器:

image005

2.3装饰器

装饰器模式可用于扩展(装饰)某个对象的功能,而无需更改其结构。 在Intellij IDEA中实现了许多装饰器。

图片006

2.4代理

在最一般的形式上,代理是一个类,它充当与其他对象的接口。

例如,这是通过FieldBreakpoint和FrameVariablesTree类使用两个代理VirtualMachineProxy和StackFrameProxy的。 使用VirtualMachineProxy接口代替实现。 但是,与FrameVariablesTree耦合的StackFrameProxyImpl并非如此。 也许可以通过重构来消除这种依赖性。

image007

2.5门面

外观模式隐藏了系统的复杂性,并提供了到客户端的接口,客户端可以使用该接口访问系统。 这是在Intellij IDEA中实现的CodeStyle外观的示例。

image008

2.6访客

访客设计模式是一种将算法与操作对象的结构分离的方法。

突出显示功能是使用访问者模式实现的。

image009

2.7策略

在某些情况下,类仅在行为上有所不同。 在这些情况下,最好将算法隔离在单独的类中,以便能够在运行时选择不同的算法。

许多类在Intellij IDEA源代码中实现策略模式:

image010

2.8建造者

这种模式允许客户对象构造一个复杂的对象。 ConrtolFlowBuilder是Intellij IDEA源代码中实现的构建器之一。

这是ControlFlowBuilder.build方法调用的方法:

image011

3.联轴器

低耦合是理想的,因为在一个应用程序区域中进行更改将需要在整个应用程序中进行较少的更改。 从长远来看,这可以减轻与修改和向应用程序添加新功能相关的大量时间,精力和成本。
这是使用接口带来的三个主要好处:

  • 接口提供了一种定义可促进重用的合同的方法。 如果一个对象实现一个接口,则该对象将符合标准。 使用另一个对象的对象称为使用者。 接口是对象与其使用者之间的契约。
  • 接口还提供一定程度的抽象,使程序更易于理解。 接口使开发人员可以开始讨论代码行为的一般方式,而不必深入探讨许多具体细节。
  • 接口强制组件之间的耦合度很低,这很容易保护接口使用者免受实现接口的类中任何实现更改的影响。

Intellij IDEA中定义了许多接口和抽象类,以强制实现低耦合:

image012

这是蓝色的在源代码的“衡量指标视图”中这些类型的分布。

image013

在“度量标准视图”中,代码​​库通过树形图表示。 Treemapping是一种使用嵌套矩形显示树状结构数据的方法。 使用的树结构是通常的代码层次结构:

  • 项目包含软件包。
  • 包中包含类型。
  • 类型包含方法和字段。

树状图视图提供了一种有用的方式来表示CQLinq请求的结果。 蓝色矩形代表此结果,因此我们可以直观地看到请求所涉及的类型。

如我们所见,几乎在所有包中都定义了接口和抽象类,这对于将包提供的功能作为合同表示很有用。

4.凝聚力

单一责任原则规定,一个阶级改变的理由不应该超过一个。 这类课程据说具有凝聚力。 LCOM值较高通常会指出内聚性较差的类别。 有几个LCOM指标。 LCOM的取值范围为[0-1]。 LCOM HS(HS代表Henderson-Sellers)的值在[0-2]范围内。 高于1的LCOM HS值应视为警报。 以下是计算LCOM指标的方法:

LCOM = 1 – (sum(MF)/M*F)
LCOM HS = (M – sum(MF)/F)(M-1)

哪里:

  • M是类中方法的数量(包括静态方法和实例方法,均包括构造函数,属性获取器/设置器,事件添加/删除方法)。
  • F是类中实例字段的数量。
  • MF是类访问特定实例字段的方法的数量。
  • Sum(MF)是该类所有实例字段上MF的总和。

这些公式背后的基本思想可以表述为:如果一个类的所有方法都使用其所有实例字段,则该类是完全内聚的,这意味着sum(MF)= M * F然后LCOM = 0且LCOMHS = 0。

高于1的LCOMHS值应视为警报。

image014

只有极少数的类型可以被认为是没有凝聚力的。

5.多线程和并发

为了使Intellij IDEA更具反应性,创建了许多线程,从而改善了用户体验。

让我们搜索直接或间接启动线程的所有方法:

image015

并发逻辑被隔离在以下软件包中:

image016

为了促进并发开发,使用了JSR166 。

以下是jsr166 jar使用的所有类型的列表:

image017

6.抽象与不稳定性图

该图背后的想法是,程序的代码元素越受大众欢迎,它应该越抽象。 换句话说,就是避免过多地直接依赖于实现,而要依赖于抽象。 流行的代码元素是指一个项目(但该想法也适用于包和类型),该项目被该程序的其他项目大量使用。

在您的代码库中使用非常流行的具体类型不是一个好主意。 这会引起程序中的某些痛苦区域,在其中更改实现可能会影响程序的很大一部分。 并且已知实现比抽象更容易演化。

下图中的主序列线(虚线)显示了如何平衡抽象性和不稳定性。 稳定的组件将位于左侧。 如果检查主序列,您会发现这样的组件应该非常抽象才能接近所需的线–另一方面,如果其抽象程度较低,则将其放置在称为“区域”的区域中痛”。

image018

只有util处于痛苦区域,这并不是真正的问题。 实际上,总的来说,实用程序库提供的实用程序类别比接口定义的功能更多。

7.开放的API和插件系统

插件的使用使您可以扩展Intellij IDEA。 提供“ openapi”罐来实现此目标。

openapi jar提供了许多接口,这些接口代表了我们可以使用并从插件扩展的所有功能。

image019

Intellij IDEA插件包含一个或多个动作。 如以下CQLinq查询所示,源代码中实现了成千上万的操作:

image020

探索现有的已实施操作可以帮助开发人员轻松开发其自定义插件。

8.使用缓存提高性能

使用缓存是优化应用程序的一种流行方法。 Intellij IDEA使用两个缓存管理器:

image021

FindInProjectTask使用CacheManager接口搜索单词。

这是FindInProjectTask.getFilesForFastWordSearch方法调用的所有方法的列表:

image022

9.使用的外部库

Intellij IDEA使用许多外部jar,以下是所有使用过的jar的列表:

image023 image024

使用外部库时,最好检查一下我们是否可以在不影响整个应用程序的情况下轻松地将第三方库换成另一个库。 有许多原因可以鼓励我们更改第三方库。 另一个库可以:

  • 具有更多功能。
  • 更加强大。
  • 更加安全。

让我们发现某些外部库是否高度耦合。

摇摆:

Swing实现了一组用于构建图形用户界面(GUI)并向Java应用程序添加丰富的图形功能和交互性的组件。 Swing组件完全用Java编程语言实现。 可插入的外观使您可以创建在各个平台上看起来相同或可以采用当前OS平台(例如Microsoft Windows,Solaris™或Linux)外观的GUI。

让我们使用直接摆动组件搜索所有类型:

image025

许多类型都直接使用摆动组件,如下面的树图所示,这些树以蓝色显示。

image026

通过另一个Gui框架来改变摆动并不容易。 即使Swing引起争议,Intellij IDEA惊人的GUI证明Swing是Gui需求的不错选择。

净值:

Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

这是使用此库的所有类型的列表:

image027

只有少数几种类型直接使用它,如果我们想用另一个库进行更改,这将非常有用。

ASM:

ASM是一个非常小且非常快的Java字节码操作框架。 它变得非常流行,许多工具都在使用它。 我们还在工具JArchitect中使用它来分析字节码。

这是直接使用ASM的所有类型的列表:

image028

作为Netty,ASM的使用被隔离在某些软件包中,我们可以轻松对其进行更改。

除了Swing以外,几乎所有其他外部jar都不与Intellij IDEA高度耦合。

10.统计

最常用的类型

了解项目中最常用的类型很有趣。 实际上,这些类型必须经过精心设计,实施和测试。 它们发生的任何变化都可能影响整个项目。

我们可以使用TypesUsingMe指标找到它们:

image029

但是,还有一个有趣的度量标准可以搜索流行类型:TypeRank。

通过将Google PageRank算法应用于类型的依存关系图来计算TypeRank值。 应用中心乘以0.15使其成为TypeRank的平均值为1。

具有较高TypeRank的类型应进行更仔细的测试,因为此类错误可能会带来更大的灾难性后果。

这是根据TypeRank指标得出的所有流行类型的结果:

image030

使用此度量标准,PsiElement成为了最常用的类型,而不是Project接口。

10.2最常用的方法:

image031

10.3方法调用许多其他方法

知道使用许多其他方法的方法很有趣。 这些方法可能会揭示设计问题。 在某些情况下,需要进行重构以使其更具可读性和可维护性。

image032

摘要

Intellij IDEA的设计和实现非常好,使用了许多模式,并实现了许多最佳实践。 探索其源代码是学习如何设计和实现应用程序的实用方法。 这比只阅读网络上的书籍和文章来提高您的设计技能要好。

JArchitect为 所有开源Java贡献者 提供了 专业许可 分析他们的代码库可能很有用。 因此,如果您想尝试一下,请 在此处 查看更多详细信息。

翻译自: https://www.javacodegeeks.com/2015/03/intellij-idea-internal-design.html

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

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

相关文章

TDD:MS自带的单元测试 之 线程模型和执行顺序

背景 我一直在呼喊“不要靠假设编程”,可是我却常常这么做。我用单元测试就是一种基于假设进行编程的反面教材,今天就下决心弄明白它。 主要想弄明白两个问题: 执行的所有单元测试方法的线程模型,是单线程?是多线程&am…

bat文件名操作_Excel按文件名制作目录,你复制粘贴花一小时,同事只要十秒搞定...

Excel有个特殊操作,那就是对文件夹中上百个文件,用Excel按照文件名制作目录,我们只需要点击对于的超链接就可以快速打开对于的文件。如上图所示,我们的文件夹中包含有26个视频和Excel文件,因为文件数量过多所以我们需要…

整数返回poj1005——I Think I Need a Houseboat

这两天一直在研究整数返回之类的问题,上午正好有机会和大家讨论一下. 原题: Description Fred Mapper is considering purchasing some land in Louisiana to build his house on. In the process of investigating the land, he learned that the state of Louisia…

偷窥JCache API(JSR 107)

这篇文章从较高的层次介绍了JCache API,并提供了一个预告片–刚够您(希望)开始对此发痒;-) 在这篇文章中...。 JCache概述 JCache API,实现 JCache API支持的(Java)平台 快速了解Oracle Coh…

canvas 圆角矩形填充_一篇文章让你学会你最“害怕”的Canvas,太有意思了

Canvas画布 基本用法<canvas idcanvas width"150" height"150"></canvas> <canvas>看起来跟img标签有点像&#xff0c;唯一不同的是它没有src属性和alt属性。实际上&#xff0c;canvas标签只有两个属性:width和height。 如果没有设置宽度…

abaqus单位_ANSYS和ABAQUS哪个好,一个例子告诉你

分别用ANSYS和ABAQUS来分析同一个题目并考察其异同点。【问题】一根悬臂梁&#xff0c;长200mm,截面是30mm*20mm的矩形(高度方向是20mm)。该梁左端固定&#xff0c;在其上面施加向下的分布力系&#xff0c;载荷集度是0.6Mpa.已知材料使用低碳钢&#xff0c;弹性模量是200GPA&am…

模型微调入门介绍一

备注&#xff1a;模型微调系列的博客部分内容来源于极客时间大模型微调训练营素材&#xff0c;撰写模型微调一系列博客&#xff0c;主要是期望把训练营的内容内化成自己的知识&#xff0c;我自己写的这一系列博客除了采纳部分训练营的内容外&#xff0c;还会扩展细化某些具体细…

npp夜光数据介绍 viirs_科研成果快报第177期:中国地区长时序AVHRR气溶胶数据的主要问题: 气溶胶反演频次与重污染天气...

中国地区长时序AVHRR气溶胶数据的主要问题&#xff1a;气溶胶反演频次与重污染天气A critical view of long-term AVHRR aerosol data record in China: Retrieval frequency and heavy pollution成果信息Minghui Tao, Rong Li, Lili Wang et al. (2020)A critical view of lon…

使用Eclipse创建一个Android程序方法

要编写Android程序&#xff0c;需要安装JDK、Eclipse和Android SDK。 Android SDK的安装路径不要在program file或program file(x86)下&#xff0c;否则在debug时会碰很奇怪的问题。最好直接放在C:\Android下。&#xff08;如果非要放在Program files下也可以&#xff0c;在ecl…

如何使用Hibernate批处理DELETE语句

介绍 在我以前的文章中 &#xff0c;我解释了批处理INSERT和UPDATE语句所需的Hibernate配置。 这篇文章将继续本主题的DELETE语句批处理。 领域模型实体 我们将从以下实体模型开始&#xff1a; Post实体与Comment具有一对多关联&#xff0c;并且与PostDetails实体具有一对一…

蓝点linux_新闻速读 gt; Windows 10 的 Linux 内核将像驱动程序一样由微软更新服务进行更新 | Linux 中国...

本文字数&#xff1a;3252&#xff0c;阅读时长大约&#xff1a;4 分钟导读&#xff1a;• Ubuntu 发行商 Canonical 将参加微软欧洲虚拟开源峰会 • 树莓派支持 Vulkan 最新进展&#xff1a;通过 70000 项测试 • 谷歌浏览器开始隐藏 URL 详细路径&#xff0c;未来地址栏将只显…

struts2-通配符和动态方法调用

通配符举例--BookAction 1 public class BookAction extends ActionSupport {2 3 public String execute() throws Exception {4 System.out.println("BookAction ********** execute()");5 return null;6 }7 /*8 * 显示图书添加页…

JavaFX技巧18:路径剪切

我最近注意到&#xff0c;我致力于ControlsFX项目的PopOver控件无法正确剪切其内容。 当我为FlexCalendarFX框架开发手风琴弹出窗口时&#xff0c;这一点变得显而易见。 每当最后一个标题窗格扩展时&#xff0c;其底角不再是圆角而是正方形。 在将红色矩形作为内容放置到标题窗…

关于erlang的套接字编程

套接字编程即熟悉的Socket编程&#xff0c;根据传输层协议&#xff0c;可分为&#xff1a;UDP协议和TCP协议.下面写一个简单的例子&#xff0c;再重新认识下它&#xff1a; 1.在同一主机节点下启动两个Erlang节点. a).在第一个Erlang节点下&#xff0c;打开端口为1234的UDP套接…

kotlin 添加第一个 集合_Flutter开发必学Dart语法篇之集合操作符函数与源码分析...

简述:在上一篇文章中&#xff0c;我们全面地分析了常用集合的使用以及集合部分源码的分析。那么这一节讲点更实用的内容&#xff0c;绝对可以提高你的Flutter开发效率的函数&#xff0c;那就是集合中常用的操作符函数。这次说的内容的比较简单就是怎么用&#xff0c;以及源码内…

在Java中确定文件类型

以编程方式确定文件的类型可能非常棘手&#xff0c;并且已经提出并实现了许多基于内容的文件标识方法。 Java中有几种可用于检测文件类型的实现&#xff0c;其中大多数很大程度上或完全基于文件的扩展名。 这篇文章介绍了Java中最常见的文件类型检测实现。 本文介绍了几种在Ja…

程序员编程艺术第十一章:最长公共子序列(LCS)问题

程序员编程艺术第十一章&#xff1a;最长公共子序列(LCS)问题 0、前言 程序员编程艺术系列重新开始创作了&#xff08;前十章&#xff0c;请参考程序员编程艺术第一~十章集锦与总结&#xff09;。回顾之前的前十章&#xff0c;有些代码是值得商榷的&#xff0c;因当时的代码只顾…

gateway 过滤器执行顺序_Gateway网关源码解析—路由(1.1)之RouteDefinitionLocator一览...

一、概述本文主要对 路由定义定位器 RouteDefinitionLocator 做整体的认识。在 《Spring-Cloud-Gateway 源码解析 —— 网关初始化》 中&#xff0c;我们看到路由相关的组件 RouteDefinitionLocator / RouteLocator 的初始化。涉及到的类比较多&#xff0c;我们用下图重新梳理下…

ERP开发中应用字符串解析实现界面翻译智能化

ERP中要实现界面多语言的功能&#xff0c;则要对各种情况的字符串进行处理并作出翻译。有些字符串的翻译是有规律可行的&#xff0c;遵循相应的模板模式&#xff0c;解析字符串&#xff0c;可以实现机器翻译的效果。 请看帐套数据库表的设计ADCOMP CREATE TABLE dbo.ADCOMP(REC…

参数详解 复制进程_如何优化PostgreSQL逻辑复制

How to Optimize PostgreSQL Logical Replication逻辑复制( Logical Replication )或 Pglogical 是表级别的复制。两者都是基于 WAL 的复制机制&#xff0c;允许在两个实例之间复制指定表的WAL 。这两个看起来让人迷惑&#xff0c;到底有什么区别呢&#xff1f; Logical Replic…