intellij idea_IntelliJ IDEA内部设计

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

这是蓝色的源代码中这些类型在Metric视图中的分布。

image013

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

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

树状图视图提供了一种有用的方式来表示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更具React性,创建了许多线程,从而改善了用户体验。

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

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

intellij idea

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

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

相关文章

mysql索引下沉_MySQL 5.6 索引条件下推优化

索引下推优化是MySQL5.6版本中新加的功能。索引条件下推(ICP)是对MySQL使用索引从表中检索行的情况的优化。如果没有ICP,存储引擎会遍历索引以查找基表中的行,并将它们返回给MySQL服务器,由server层再做一波筛选。启用ICP后,如果只…

C语言 | 函数执行成功时,return 1 还是return 0?

今天分享的内容是关于函数执行成功,返回0还是1的讨论~基本上,没有人会将大段的C语言代码全部塞入 main() 函数,更好的做法是按照复用率高,耦合性低的原则,尽可能的将代码拆分不同的功能模块,并封装成函数。…

jcache_窥探JCache API(JSR 107)

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

redis 启动加载mysql_Redis分析系列:启动加载过程

从本篇文章开始(命名为Redis分析系列),将会通过分析Redis的源代码(以Redis 2.2.0 RC1为准),来对它的内部实现做一些探讨。本文主要介绍Redis启动加载过程,总体上可以分为如下几步:1. 初始化全局服务器配置2. 加载配置文件(如果指定…

c 文件怎么进行读取和写入操作?

C >>和<<读写文本文件&#xff1a;fstream 或者 ifstream 类负责实现对文件的读取&#xff0c;它们内部都对 >> 输出流运算符做了重载&#xff1b;同样&#xff0c;fstream 和 ofstream 类负责实现对文件的写入&#xff0c;它们的内部也都对 << 输出流…

mysql+误操作怎么恢复_Mysql误操作恢复流程

一、开启binlog。show variables like log_bin;#vim /etc/my.cnf在[mysqld]中加入log-bin mysql-binlog-bin /usr/local/mysql/log/mysql-bin.log重启mysql服务#service mysqld stop#service mysqld start二、数据写入建库create database …

drools6.5_Drools 6.2.0.Final发布

drools6.5我们很高兴地宣布最新&#xff0c;最出色的Drools 6.2.0.Final版本。 特别是此发行版更加注重改进的可用性和功能&#xff0c;这些功能使项目更易于使用&#xff08;和采用&#xff09;。 新功能包括对工作台UI的大量改进&#xff0c;对社交活动和插件管理的支持以及…

c程序编写x的y次方的方法

c程序怎么编写x的y次方?C语言pow()函数&#xff1a;求x的y次方&#xff08;次幂&#xff09;头文件&#xff1a;#include pow() 函数用来求 x 的 y 次幂&#xff08;次方&#xff09;&#xff0c;其原型为&#xff1a;double pow(double x, double y);pow()用来计算以x 为底的…

python redis pipeline使用方法_python使用pipeline批量读写redis的方法

用了很久的redis了。随着业务的要求越来越高。对redis的读写速度要求也越来越高。正好最近有个需求(需要在秒级取值1000的数据)&#xff0c;如果对于传统的单词取值&#xff0c;循环取值&#xff0c;消耗实在是大&#xff0c;有小伙伴可能考虑到多线程&#xff0c;但这并不是最…

jboss fuse 教程_JBoss Fuse –一些鲜为人知的技巧

jboss fuse 教程TL; DR 将Java静态调用公开为Karaf Shell本机命令 在部署时覆盖OSGi标头 在使用OSGi片段部署时间后覆盖OSGi标头 将Java静态调用公开为Karaf Shell本机命令 作为必须与支持人员和客户进行协作的软件工程师的一部分&#xff0c;我经常发现自己需要从无法访问…

8条嵌入式C语言编程小知识总结

1. 流水线被指令填满时才能发挥最大效能&#xff0c;即每时钟周期完成一条指令的执行(仅指单周期指令)。如果程序发生跳转&#xff0c;流水线会被清空&#xff0c;这将需要几个时钟才能使流水线再次填满。因此&#xff0c;尽量少的使用跳转指令可以提高程序执行效率&#xff0c…

c语言函数的三种调用方式是什么?

函数的三种调用方式&#xff1a;1、函数作为表达式中的一项出现在表达式中&#xff0c;例“zmax(x,y)”&#xff1b;2、函数作为一个单独的语句&#xff0c;例“printf("%d",a)”&#xff1b;3、函数作为调用另一个函数时的实参&#xff0c;例“printf("%d"…

CF1913D. Array Collapse [dp+单调栈+前缀和]

传送门 [前题提要]:感觉dp还是很显然的,感觉单调栈也不是很难想,但是VP的时候脑子比较乱,dp方程想偏了,没写出来… 看完题目,不难发现应该存在一种递推关系.因为会发现最后剩下来的必然是原序列的一种子序列,然后这种子序列计数的问题.应该想到使用dp计数. 刚开始我的想法是使…

弱口令扫描工具mysql ftp_基于端口的弱口令检测工具--iscan

iscan: 基于端口的弱口令检测工具亲手打造了一款基于端口的弱口令检测工具&#xff0c;使用python进行编写&#xff0c;主要可以用于渗透测试中常见服务端口弱口令的检测。目前支持以下服务&#xff1a;系统弱口令&#xff1a;ftp、ssh、telnet、ipc$数据库弱口令&#xff1a;m…

javafx 剪切板_JavaFX技巧18:路径剪切

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

用于单片机的几种C语言算法

单片机主要作用是控制外围的器件&#xff0c;并实现一定的通信和数据处理。虽然单片机不擅长实现算法和进行复杂的运算&#xff0c;但在某些特定场合&#xff0c;不可避免地要用到数学运算。比如&#xff1a;在单片机进行数据采集时&#xff0c;会遇到数据的随机误差&#xff0…

jmh 基准测试_JMH:如何设置和运行JMH基准

jmh 基准测试健康警告&#xff01; 这篇文章描述了如何设置和运行简单的JMH基准测试。 众所周知&#xff0c;微基准测试很难正确设置&#xff0c;即使您确实正确设置了&#xff08;通过使用JMH之类的工具&#xff09;&#xff0c;它们仍然会产生误导。 仅仅因为您的代码在极端孤…

java super是什么意思_java中Super到底是什么意思?必须举例说明!

[学习笔记]3."超"关键字(super keyword)Super是一个参考(或说指针)指向他紧邻的父类(见下面的例子)。用super可以指向被隐藏的父类的同名成员。3.1 super指向父类的成员注意&#xff1a; 下例中&#xff1a;子类和父类都有i&#xff0c;我们一共有两个i&#xff0c;用…

嵌入式开发中C语言编程要点简述!

在嵌入式Linux的C语言开发中&#xff0c;C语言的基本编程依然是最重要的内容。除此之外&#xff0c;与一般的C语言编程相比&#xff0c;嵌入式Linux的C语言编程有以下一些要点&#xff1a;1、库函数与系统调用在进行C语言编程的时候&#xff0c;使用库函数是不可避免的。关于使…

java编译源文件_在java编程中用什么命令来编译java源文件 可以将源文件编译成字节码文件,求答案 。...

展开全部答案如下&#xff1a;1 、javac 选 A2、 int 选 D int 为关键字3、 4 选 B4、 15 选C5 、界面类型 选D6 、age[0] 选B7、 class 选A8 、java B9、 abstract 选B10 、false 选D1、 错&#xff0c;区分大小写2、 对3 、错e68a843231313335323631343130323136353331333365…