Kotlin 中的單例模式(Singleton)與對象聲明

在 Kotlin 中,類描述的是一種通用結構,可以多次實例化,也可以用多種方式實例化。但有時我們只需要單個實例,不多不少。單例模式能幫你更好地組織代碼,把相關的方法聚合在一起。

單例模式是什么?

單例模式是一種設計模式,保證一個類只有一個實例,并提供全局訪問點。這意味著你可以在代碼的任何地方獲取這個單例類的實例。打個比方,就像大家一起玩棋盤游戲,所有玩家都在同一個“棋盤”上進行操作,這個棋盤就相當于游戲的全局狀態。

單例的主要特征:

  • 單例類只有一個實例。

  • 單例類提供一個全局訪問點。

Kotlin 的對象聲明(object declaration)

單例模式非常有用,而 Kotlin 為單例提供了專門的語法結構:object 聲明。這是一種特殊的類聲明,使用關鍵字 object 創建單例。Kotlin 自動處理所有復雜步驟,你只需要用 object 聲明即可,無需手動實現單例模式。

object PlayingField {fun getAllPlayers(): Array<Player> {/* ... */}fun isPlayerInGame(player: Player): Boolean {/* ... */}}

解釋:

使用 object 聲明時,構造函數不可用,因為 Kotlin 自動完成。你可以通過 PlayingField 直接訪問這個單例實例,它在代碼任何地方調用都指向同一個對象。

示例:

fun startNewGameTurn() {val players = PlayingField.getAllPlayers()if (players.size < 2) {return println("The game cannot be continued without players")}for (player in players) {nextPlayerTurn(player)}
}fun nextPlayerTurn(player: Player) {if (!PlayingField.isPlayerInGame(player)) {return println("Current player lost. Next...")}/* 玩家行動 */
}

嵌套對象(Nested object)

有時候你想創建一個和另一個類相關聯的單例。例如,游戲中有 Player 類,代表不同的角色,這些角色有共享的屬性,比如默認速度。你如何保存這些共享信息呢?

你可以簡單地創建一個單例對象:

object PlayerProperties {/* 默認速度,每回合移動7格 */val defaultSpeed = 7fun calcMovePenalty(cell: Int): Int {/* 計算移動速度懲罰 */}
}

但如果項目里有許多類似的單例,代碼會變得難讀。更好的做法是將單例嵌套到相關類中。

class Player(val id: Int) {object Properties {val defaultSpeed = 7fun calcMovePenalty(cell: Int): Int {/* 計算移動懲罰 */}}
}/* 輸出 7 */
println(Player.Properties.defaultSpeed)

Properties 對象作用域是 Player,只能通過 Player.Properties 訪問。這種方式讓單例和類有明確的關聯。

你還可以在外部類中使用嵌套對象的屬性:

class Player(val id: Int) {object Properties {val defaultSpeed = 7}val superSpeed = Properties.defaultSpeed * 2 // 14
}

但反過來是不行的——嵌套對象中不能訪問外部類的實例成員:

class Player(val id: Int) {    val speed = 7object Properties {val defaultSpeed = speed // 錯誤,不能訪問外部類實例屬性}
}

這和其他語言的 static 類似,Kotlin 沒有默認的靜態成員,但可以用嵌套對象來達到類似效果。


編譯時常量(Compile-time constants)

如果某個只讀屬性永遠不會改變,我們稱它為常量。可以使用 const 關鍵字聲明編譯時常量:

object Languages {const val FAVORITE_LANGUAGE = "Kotlin"
}

要求:

  • 必須是基本類型或 String。

  • 不能有自定義 getter。

  • 命名用全大寫加下劃線(SCREAMING_SNAKE_CASE)。

比如游戲里的默認速度可以寫成:

object Properties {const val DEFAULT_SPEED = 7
}

訪問:

println(Properties.DEFAULT_SPEED) // 輸出 7

為什么不都用頂層常量?因為大量無關聯的頂層常量會讓代碼混亂,影響閱讀。最好把和某個對象相關的常量放到對應的對象里。


對象與嵌套對象的擴展

你可以在一個類里聲明多個對象,比如:

class Player(val id: Int) {object Properties {val defaultSpeed = 7fun calcMovePenalty(cell: Int): Int { /* ... */ }}object Factory {fun create(playerId: Int): Player {return Player(playerId)}}
}println(Player.Properties.defaultSpeed)    // 7
println(Player.Factory.create(13).id)      // 13

這里的 Factory 是工廠模式,用來創建 Player 實例。你也可以在一個對象內部聲明多個對象,用來組織單例數據:

object Game {object Properties {val maxPlayersCount = 13val maxGameDurationInSec = 2400}object Info {val name = "My super game"}
}

數據對象(Data object)

普通的對象聲明打印會顯示類名和哈希碼:

object MyObjectfun main() {println(MyObject) // MyObject@1f32e575
}

如果用 data 修飾單例對象,會生成更友好的方法:

data object MySingletonfun main() {println(MySingleton) // MySingleton
}

注意,data object 不是數據類,不能復制(沒有 copy() 方法),也沒有組件函數,因為單例不允許多實例。


總結

Kotlin 中,object 聲明是創建單例的標準方式,也可以用嵌套對象關聯類本身,而非類的實例。合理使用它們可以讓代碼結構更清晰,提升可讀性和可維護性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90208.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90208.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90208.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Shell 編程基礎入門從認識到實戰

對于剛接觸 Linux 或 Unix 系統的開發者來說&#xff0c;Shell 腳本往往是自動化操作的第一道門檻。它不像 Python 那樣語法簡潔&#xff0c;也不像 Java 那樣有完善的面向對象體系&#xff0c;但卻能以極少的代碼實現強大的系統管理功能。本文將從 Shell 的基本概念講起&#…

混合遺傳粒子群算法在光伏系統MPPT中的應用研究

混合遺傳粒子群算法在光伏系統MPPT中的應用研究 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家&#xff0c;覺得好請收藏。點擊跳轉到網站。 摘要 本文針對光伏系統最大功率點跟蹤(MPPT)問題&#xff0…

機器視覺的布料絲印應用

在紡織印染行業&#xff0c;布料絲印工藝的精度直接決定產品外觀質量與市場競爭力。傳統絲印設備依賴機械定位與人工校準&#xff0c;面對高密度圖案、柔性面料或復雜紋理時&#xff0c;易出現套色偏移、油墨滲透不均等問題&#xff0c;導致良品率波動與生產成本攀升。 隨著機…

前端常用類庫

常用類庫 類庫作用 類庫可以幫助我們快速實現項目業務的開發與功能的實現, 幫助我們解放勞動力提高生產效率, 前端中的類庫與框架都是由原生javascript編寫, 提供給其他開發者應用于某一業務環境或者需求。一般有開發者/團隊開源維護. 優秀的類庫需要具備高度封裝可用, 穩定, …

通俗易懂循環神經網絡(RNN)指南

本文用直觀類比、圖表和代碼&#xff0c;帶你輕松理解RNN及其變體&#xff08;LSTM、GRU、雙向RNN&#xff09;的原理和應用。什么是循環神經網絡 循環神經網絡&#xff08;Recurrent Neural Network, RNN&#xff09;是一類專門用于處理序列數據的神經網絡。與前饋神經網絡不同…

【SVM】支持向量機實例合集

基于Java的SVM(支持向量機)實例合集 以下是一個基于Java的SVM(支持向量機)實例合集,包含核心代碼示例和應用場景說明。這些例子基于流行的機器學習庫(如LIBSVM、Weka、JSAT)實現。 數據準備與加載 使用LIBSVM格式加載數據集: // 加載LIBSVM格式數據 svm_problem pr…

Python100個庫分享第38個—lxml(爬蟲篇)

目錄專欄導讀&#x1f4da; 庫簡介&#x1f3af; 主要特點&#x1f6e0;? 安裝方法Windows安裝Linux/macOS安裝驗證安裝&#x1f680; 快速入門基本使用流程HTML vs XML解析&#x1f50d; 核心功能詳解1. XPath選擇器2. CSS選擇器支持3. 元素操作&#x1f577;? 實戰爬蟲案例…

imx6ull-系統移植篇17——linux頂層 Makefile(上)

目錄 前言 頂層 Makefile 源碼簡析 版本號 MAKEFLAGS 變量 命令輸出 靜默輸出 設置編譯結果輸出目錄 代碼檢查 模塊編譯 設置目標架構和交叉編譯器 調用 scripts/Kbuild.include 文件 交叉編譯工具變量設置 頭文件路徑變量 導出變量 make xxx_defconfig 過程 …

OpenCV 官翻6 - Computational Photography

文章目錄圖像去噪目標理論OpenCV中的圖像去噪1、cv.fastNlMeansDenoisingColored()2、cv.fastNlMeansDenoisingMulti()附加資源圖像修復目標基礎概念代碼補充資源練習高動態范圍成像&#xff08;HDR&#xff09;目標理論基礎曝光序列HDR1、將曝光圖像加載到列表中2、將曝光序列…

APT32F1732RBT8愛普特微電子 32位MCU國產芯片 智能家居/工業控制 首選

APT32F1732RBT8 愛普特微電子&#xff0c;32位MCU國產芯片一、產品簡介APT32F1732RBT8 是愛普特微電子&#xff08;APT&#xff09;推出的高性能32位ARM Cortex-M0內核MCU&#xff0c;主頻高達48MHz&#xff0c;內置64KB Flash8KB RAM&#xff0c;專為智能家居、工業控制、消費…

Smart Tomcat

本篇博客的內容是教你借助idea中的插件,把tomcat集成到idea中安裝 Smart Tomcat 插件搜索下載 ,如果一直處于加載界面,就嘗試一下科學上網配置 Smart Tomcat 插件 點擊右上角的 "Add Configuration"選擇左側的 "Smart Tomcat" 在 Name 這一欄填寫一個名字(…

Linux_shell編寫

title: Linux_4 shell編寫 shell pwd (/root/A/2025_7/19/myshell) 首先需要設計命令行提示 &#xff08;MakeCommandLine()&#xff09; 首先獲取相關信息 getenv(“name”) // 獲取用戶名 const char* GetUserName() {const char* name getenv("USER");if (name …

【數據結構】棧的深入解析--用C語言實現

文章目錄1.棧的概念2.棧的底層結構3.棧的功能4.棧的實現4.1.棧結構的定義4.2.棧的初始化4.3.棧的銷毀4.4.入棧4.5.出棧4.6.取棧頂元素4.7.獲取棧中有效元素個數5.完整代碼Stack.hStack.cmain.c運行結果1.棧的概念 是一種特殊的線性表&#xff0c;只允許數據在固定的一段進行插…

Git倉庫核心概念與工作流程詳解:從入門到精通

Git倉庫的基本概念版本庫&#xff08;Repository&#xff09;是Git的核心概念&#xff0c;你可以簡單理解為一個被Git管理的目錄。這個目錄里的所有文件都能被Git跟蹤&#xff0c;記錄每次修改和刪除&#xff0c;讓你可以隨時追溯歷史或在未來某個時刻"還原"文件。Gi…

Web開發 05

1 React庫&#xff08;人話詳解版&#xff09;別慌&#xff0c;React 剛接觸時是會有點懵&#xff0c;咱們用 “人話 類比” 一步步拆&#xff1a;核心概念先抓牢組件&#xff08;Component&#xff09;把它想成 “樂高積木”&#xff0c;比如做個社交 App&#xff0c;頂部導航…

RustDesk 自建中繼服務器教程(Mac mini)

&#x1f4d6; 教程目標 在家里的 Mac mini 上部署 RustDesk 中繼服務器 (hbbs hbbr)&#xff0c;讓你從辦公室、筆電或手機 低延遲、安全 地遠程控制家里的 Windows 和 Mac mini。 ? 不依賴第三方服務器 ? 支持 P2P 和中繼雙模式 ? 全流量可控、跨平臺 &#x1f3d7;? 架…

數據庫—修改某字段默認值

前言有時候&#xff0c;數據庫的字段默認值沒有正確設置&#xff0c;這時候需要改默認值。以下是我做的改默認值的記錄&#xff0c;希望對網友有所幫助。1.SQL SERVER下面的示例假設你要修改名為 YourColumnName 的字段&#xff0c;并為其設置一個新的默認值 NewDefaultValue。…

Spring快速整合Mybatis

MyBatis是一個優秀的持久層框架&#xff0c;Spring則是廣泛使用的Java應用框架。可以將兩者整合可以充分發揮各自的優勢。 1、Spring整合MyBatis的基本配置 添加依賴&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spri…

基于深度學習的語音識別:從音頻信號到文本轉錄

前言 語音識別&#xff08;Automatic Speech Recognition, ASR&#xff09;是人工智能領域中一個極具挑戰性和應用前景的研究方向。它通過將語音信號轉換為文本&#xff0c;為人們提供了更加自然和便捷的人機交互方式。近年來&#xff0c;深度學習技術在語音識別領域取得了顯著…

本地部署Nacos開源服務平臺,并簡單操作實現外部訪問,Windows 版本

Nacos 是一款阿里開源的動態服務發現、配置、管理平臺&#xff0c;擁有易于集成、高可用與可擴展等特點。它提供了動態服務注冊和發現能力&#xff0c;使得服務自動注冊到服務器并且消費真能夠發現提供者。本文將詳細介紹如何在本地安裝 Nacos &#xff0c;以及結合nat123端口映…