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…

JS下载图片保存在本地

const imgUrl "";// 图片链接const a document.createElement(a);// 这里是将url转成blob地址,fetch(imgUrl) // 跨域时会报错.then(res > res.blob()).then(blob > { // 将链接地址字符内容转变成blob地址a.href URL.createObjectURL(blob);a.…

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…

electron IPC通信报错Uncaught (in promise) Error: An object could not be cloned.

项目场景: electronreact 问题描述 electron 中用IPC通信 Uncaught (in promise) Error: An object could not be cloned. e Error: An object could not be cloned.at EventEmitter.i.invoke (node:electron/js2c/sandbox_bundle:33)at uploadImg (YakitPluginI…

Linux C中发现无法连接到math.h中的数学函数解决办法

Linux 下使用数学函数 今天在编译一个用到log函数的c文件时,遇到一个错误:/tmp/ccQuh0ns.o(.text0x2bb): In function Compute:: undefined reference to log到网上查了一下这个问题,原因及解决方法如下:出现这个错误是因为编译器…

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

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

通过流而不是列表

开幕式免责声明&#xff1a;这并不总是一个好主意。 我将介绍这个主意&#xff0c;以及为什么它是一个好主意的一些原因&#xff0c;但随后我将讨论一些不太理想的实例。 懒惰 如您所知&#xff0c;我在Python中涉猎的程度几乎与在Java中一样。 我一发现Python就很喜欢生成器。…

react-infinite-scroll-component 第二次加载无法触发next

react-infinite-scroll-component 是一款滚动加载插件&#xff0c;在页面滚动的时候加载数据&#xff0c;在使用过程遇到一个坑。 坑的描述&#xff1a; 在页面滚动的时候&#xff0c;infiniteScroll页面数是自动1,打个比方说&#xff0c;页面加载到第三页&#xff0c;infinit…

linux查看文件大小和查看磁盘使用情况

1、df -h 显示目前所有文件系统的可利用空间及和使用情况。参数 -h表示人类可以看懂的格式输出 2、du -h --max-depth1 目录 查询指定文件夹下各个文件夹或文件的大小 3、du -sh test/ 或 du -sm * |sort -n 查看文件目录的大小和数量&#xff0c;并且可以按大小排序 du和df的…

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

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

electron nodejs上传文件获取文件流

使用antd upload组件&#xff0c;electron中ipcRenderer.invoke无法传递文件流&#xff1b; 传文件路径过去&#xff0c;然后使用nodejs获取文件流 // 创建数据流const readerStream fs.createReadStream(path)const formData new FormData()formData.append("file_name…

使用junit做其他事情

junit&#xff01;单元测试 Junit是Java单元测试框架。 通常&#xff0c;我们将其用于单元测试&#xff0c;但是很多时候我们也使用它来执行集成测试。 主要区别在于&#xff0c;单元测试可测试单个单元&#xff0c;而集成测试则可测试不同类如何协同工作。 这样&#xff0c;集…

转行python能拿到多少钱_想转行学python过来人提醒大家几点

因为目前python非常火&#xff0c;应用也非常广泛&#xff0c;是目前最火的行业之一&#xff0c;竞争很大&#xff0c;工资很高&#xff0c;未来发展也极好。Python 现在到底有多热呢&#xff1f;我觉得我们可以看以下的这2组数据。第一&#xff1a;Python 排名稳居前五得益于 …

纯前端 导出excel 插件xlsx和file-saver

使用插件 xlsx 导出表格&#xff0c;file-saver保存文件 vue-element-admin,源码中找的&#xff1b;导出上万条数据还是很快的 gitHub地址,/vendor/Export2Excel的js文件 使用方法 export_json_to_excel({header: res.header,data: res.exportData,filename: ${fileName}1-$…

用Java创建自己的AOP

介绍 如您所知&#xff0c;AOP是Spring框架提供的最好的功能之一&#xff0c;它在实现跨领域关注的同时提供了最大的灵活性。 您是否想到过AOP在Spring如何工作&#xff1f; 有时这是高级技术面试时要问的问题。 有时&#xff0c;仅涉及核心Java时&#xff0c;这个问题变得更加…

linux中常用的头文件

#include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件。 #include <asm/***.h> 是在linux-2.6.29/arch/arm/include/asm下面寻找源文件。 #include <mach/***.h> 是在linux-2.6.29/arch/arm/mach-s3c2410/include/mach下面寻找源文件。 #in…

java的文本框如何回车键触发按钮_java回车触发按钮的代码

使用的时候&#xff0c;只要将SwingUtils .enterPressesWhenFocused(JButton)这样就可以实现回车时候&#xff0c;触发按钮。另外文本输入框回车触发事件则是&#xff1a;SwingUtils .enterPressesWhenFocused(JTextField textField,ActionListener actionListener) 。其中acti…

Typescript Interface 覆盖继承的接口定义

type Merge<M, N> Omit<M, Extract<keyof M, keyof N>> & N;使用方式 interface A {name: string;color?: string; } type B Merge<A, {name: string | number;favorite?: boolean; }>;参考地址