Kotlin开发IntelliJ插件:如何用非var属性优雅初始化单例状态?
优雅实现IntelliJ插件全局非空单例状态
针对你遇到的问题,这里提供一种符合Kotlin设计意图的方案,既能避免可空var的繁琐断言,又不用依赖投机性的by lazy写法:
1. 封装非空状态的数据类
首先用一个数据类把所有需要的状态打包,确保内部属性都是非空的val:
import com.intellij.openapi.project.Project import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx data class ProjectContext( val project: Project, val path: String, val fileManager: FileEditorManagerEx )
2. 实现全局单例状态持有者
创建一个单例对象,内部用lateinit var持有ProjectContext,但对外只暴露非空的val属性,同时限制初始化只能执行一次:
object ProjectState { private lateinit var context: ProjectContext // 对外暴露的非空属性,直接从初始化后的context获取 val project: Project get() = context.project val path: String get() = context.path val fileManager: FileEditorManagerEx get() = context.fileManager // 仅允许在ProjectActivity中调用的初始化方法 fun initialize(project: Project) { if (::context.isInitialized) { throw IllegalStateException("ProjectState已完成初始化,不可重复调用") } // 提前校验basePath非空,把异常抛出在初始化阶段 val basePath = project.basePath ?: throw IllegalStateException("项目根路径为空,无法初始化状态") context = ProjectContext( project = project, path = basePath, fileManager = FileEditorManagerEx.getInstanceEx(project) ) } }
3. 在扩展点完成初始化
修改你的ProjectActivity实现,调用ProjectState的初始化方法:
import com.intellij.openapi.project.ProjectActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class Context : ProjectActivity { override suspend fun execute(project: Project) { withContext(Dispatchers.IO) { ProjectState.initialize(project) } } }
4. 全局无断言使用状态
现在你可以直接在代码的任何地方使用非空属性,再也不用!!断言:
fun what_i_want() { create_workspace(ProjectState.fileManager.editorSplitters) }
方案优势
- 符合Kotlin设计:用不可变的
val属性保证状态不被意外修改,避免可空类型的繁琐处理 - 安全性高:初始化阶段就完成所有非空校验,避免使用时才出现空指针异常;同时限制重复初始化,防止状态被覆盖
- 结构清晰:将状态封装在数据类中,单例只负责状态的持有和暴露,职责单一
内容的提问来源于stack exchange,提问作者Jarek
相关产品推荐
相关产品推荐

