程序结构
概述
本章介绍Kotlin程序的组织结构,包括包、文件、类、对象、接口等核心概念。理解这些结构有助于编写组织良好、可维护的Kotlin代码。
包结构
包声明
kotlin
// 文件:src/main/kotlin/com/example/myapp/models/User.kt
package com.example.myapp.models
class User(val name: String, val email: String)包的组织原则
kotlin
// 按功能组织包结构
com.example.myapp/
├── models/ // 数据模型
│ ├── User.kt
│ ├── Product.kt
│ └── Order.kt
├── services/ // 业务逻辑
│ ├── UserService.kt
│ └── OrderService.kt
├── repositories/ // 数据访问
│ ├── UserRepository.kt
│ └── OrderRepository.kt
├── controllers/ // 控制器(Web应用)
│ └── UserController.kt
└── utils/ // 工具类
├── DateUtils.kt
└── StringUtils.kt顶级声明
kotlin
// 文件:MathUtils.kt
package com.example.utils
// 顶级函数
fun calculateArea(radius: Double): Double = Math.PI * radius * radius
// 顶级属性
const val PI_APPROXIMATION = 3.14159
// 顶级类
class Calculator {
fun add(a: Int, b: Int) = a + b
}
// 顶级对象
object MathConstants {
const val E = 2.71828
const val GOLDEN_RATIO = 1.61803
}类结构
基本类定义
kotlin
// 简单类
class Person {
// 属性
var name: String = ""
var age: Int = 0
// 方法
fun introduce() {
println("Hi, I'm $name, $age years old")
}
}
// 带主构造函数的类
class Student(val name: String, val studentId: String) {
// 次构造函数
constructor(name: String, studentId: String, grade: Int) : this(name, studentId) {
this.grade = grade
}
// 属性
var grade: Int = 1
// 初始化块
init {
println("Student $name created with ID $studentId")
}
// 方法
fun study(subject: String) {
println("$name is studying $subject")
}
}类的可见性修饰符
kotlin
// 默认是public
class PublicClass
// 内部可见(同一模块)
internal class InternalClass
// 私有类(同一文件)
private class PrivateClass
class Example {
// 公共属性
val publicProperty = "public"
// 内部属性
internal val internalProperty = "internal"
// 保护属性(子类可见)
protected val protectedProperty = "protected"
// 私有属性
private val privateProperty = "private"
// 公共方法
fun publicMethod() {}
// 私有方法
private fun privateMethod() {}
}接口
接口定义和实现
kotlin
// 接口定义
interface Drawable {
// 抽象属性
val color: String
// 抽象方法
fun draw()
// 带默认实现的方法
fun getInfo(): String = "Drawable object with color $color"
// 带默认实现的属性
val isVisible: Boolean
get() = true
}
// 实现接口
class Circle(override val color: String, val radius: Double) : Drawable {
override fun draw() {
println("Drawing a $color circle with radius $radius")
}
override fun getInfo(): String {
return "Circle: ${super.getInfo()}, radius=$radius"
}
}
// 多接口实现
interface Movable {
fun move(x: Int, y: Int)
}
class MovableCircle(
override val color: String,
val radius: Double
) : Drawable, Movable {
private var x = 0
private var y = 0
override fun draw() {
println("Drawing circle at ($x, $y)")
}
override fun move(x: Int, y: Int) {
this.x = x
this.y = y
}
}函数式接口 (SAM)
kotlin
// 函数式接口
fun interface StringProcessor {
fun process(input: String): String
}
// 使用lambda实现
fun main() {
val upperCaseProcessor = StringProcessor { it.uppercase() }
val result = upperCaseProcessor.process("hello")
println(result) // HELLO
// 直接传递lambda
processString("world") { it.reversed() }
}
fun processString(input: String, processor: StringProcessor): String {
return processor.process(input)
}对象声明和表达式
对象声明 (Singleton)
kotlin
// 单例对象
object DatabaseManager {
private var isConnected = false
fun connect() {
if (!isConnected) {
println("Connecting to database...")
isConnected = true
}
}
fun disconnect() {
if (isConnected) {
println("Disconnecting from database...")
isConnected = false
}
}
fun isConnected() = isConnected
}
// 使用单例对象
fun main() {
DatabaseManager.connect()
println("Connected: ${DatabaseManager.isConnected()}")
DatabaseManager.disconnect()
}伴生对象
kotlin
class User private constructor(val name: String, val email: String) {
companion object Factory {
private var userCount = 0
// 工厂方法
fun createUser(name: String, email: String): User {
userCount++
return User(name, email)
}
fun createGuestUser(): User {
return createUser("Guest", "guest@example.com")
}
// 伴生对象属性
fun getUserCount() = userCount
}
override fun toString() = "User(name='$name', email='$email')"
}
fun main() {
val user1 = User.createUser("Alice", "alice@example.com")
val user2 = User.createGuestUser()
println("Users created: ${User.getUserCount()}")
println(user1)
println(user2)
}对象表达式 (匿名对象)
kotlin
interface ClickListener {
fun onClick()
fun onLongClick()
}
fun main() {
// 匿名对象实现接口
val button = object : ClickListener {
override fun onClick() {
println("Button clicked")
}
override fun onLongClick() {
println("Button long clicked")
}
}
button.onClick()
button.onLongClick()
// 匿名对象继承类
val customList = object : ArrayList<String>() {
override fun add(element: String): Boolean {
println("Adding element: $element")
return super.add(element)
}
}
customList.add("Hello")
customList.add("World")
}枚举类
基本枚举
kotlin
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF),
YELLOW(0xFFFF00);
fun getHexString(): String = "#${rgb.toString(16).padStart(6, '0')}"
}
fun main() {
// 使用枚举
val direction = Direction.NORTH
println("Direction: $direction")
// 枚举属性和方法
val red = Color.RED
println("Red RGB: ${red.rgb}")
println("Red Hex: ${red.getHexString()}")
// 枚举遍历
println("All colors:")
for (color in Color.values()) {
println("${color.name}: ${color.getHexString()}")
}
}枚举的高级特性
kotlin
enum class Planet(val mass: Double, val radius: Double) {
MERCURY(3.303e+23, 2.4397e6),
VENUS(4.869e+24, 6.0518e6),
EARTH(5.976e+24, 6.37814e6),
MARS(6.421e+23, 3.3972e6);
// 枚举类中的方法
fun surfaceGravity(): Double {
val G = 6.67300E-11
return G * mass / (radius * radius)
}
fun surfaceWeight(otherMass: Double): Double {
return otherMass * surfaceGravity()
}
companion object {
fun findByMass(mass: Double): Planet? {
return values().find { it.mass == mass }
}
}
}
fun main() {
val earthWeight = 175.0
val mass = earthWeight / Planet.EARTH.surfaceGravity()
println("Weight on different planets:")
for (planet in Planet.values()) {
val weight = planet.surfaceWeight(mass)
println("${planet.name}: %.2f".format(weight))
}
}密封类
密封类定义
kotlin
// 密封类表示受限的类层次结构
sealed class Result<out T>
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
object Loading : Result<Nothing>()
// 使用密封类
fun handleResult(result: Result<String>) {
when (result) {
is Success -> println("Success: ${result.data}")
is Error -> println("Error: ${result.exception.message}")
Loading -> println("Loading...")
// 不需要else分支,编译器知道所有可能的子类
}
}
fun main() {
val results = listOf(
Success("Data loaded successfully"),
Error(RuntimeException("Network error")),
Loading
)
results.forEach { handleResult(it) }
}密封接口
kotlin
sealed interface UIEvent
data class ButtonClick(val buttonId: String) : UIEvent
data class TextInput(val text: String) : UIEvent
object ScreenLoad : UIEvent
class UIEventHandler {
fun handle(event: UIEvent) {
when (event) {
is ButtonClick -> println("Button ${event.buttonId} clicked")
is TextInput -> println("Text entered: ${event.text}")
ScreenLoad -> println("Screen loaded")
}
}
}数据类
数据类定义
kotlin
// 数据类自动生成equals, hashCode, toString, copy等方法
data class Person(
val name: String,
val age: Int,
val email: String
) {
// 数据类也可以有自定义方法
fun isAdult(): Boolean = age >= 18
// 数据类可以有次构造函数
constructor(name: String, age: Int) : this(name, age, "")
}
fun main() {
val person1 = Person("Alice", 25, "alice@example.com")
val person2 = Person("Alice", 25, "alice@example.com")
val person3 = person1.copy(age = 26) // 复制并修改
// 自动生成的方法
println("person1 == person2: ${person1 == person2}") // true
println("person1: $person1") // 自动生成的toString
// 解构声明
val (name, age, email) = person1
println("Name: $name, Age: $age, Email: $email")
// 自定义方法
println("Is adult: ${person1.isAdult()}")
}内联类 (Value Classes)
kotlin
// 内联类提供类型安全的包装,没有运行时开销
@JvmInline
value class UserId(val value: String)
@JvmInline
value class Email(val value: String) {
init {
require(value.contains("@")) { "Invalid email format" }
}
fun getDomain(): String = value.substringAfter("@")
}
fun processUser(userId: UserId, email: Email) {
println("Processing user ${userId.value} with email ${email.value}")
println("Email domain: ${email.getDomain()}")
}
fun main() {
val userId = UserId("user123")
val email = Email("user@example.com")
processUser(userId, email)
// 类型安全:不能混淆参数
// processUser(email, userId) // 编译错误
}嵌套类和内部类
嵌套类
kotlin
class Outer {
private val outerProperty = "Outer property"
// 嵌套类(静态)
class Nested {
fun doSomething() {
println("Nested class method")
// println(outerProperty) // 编译错误:无法访问外部类成员
}
}
// 内部类
inner class Inner {
fun doSomething() {
println("Inner class method")
println("Accessing: $outerProperty") // 可以访问外部类成员
}
}
}
fun main() {
// 创建嵌套类实例
val nested = Outer.Nested()
nested.doSomething()
// 创建内部类实例
val outer = Outer()
val inner = outer.Inner()
inner.doSomething()
}扩展
扩展函数
kotlin
// 为String类添加扩展函数
fun String.isPalindrome(): Boolean {
val cleaned = this.lowercase().replace(" ", "")
return cleaned == cleaned.reversed()
}
// 为List添加扩展函数
fun <T> List<T>.secondOrNull(): T? = if (size >= 2) this[1] else null
// 扩展属性
val String.wordCount: Int
get() = this.split("\\s+".toRegex()).size
fun main() {
val text = "A man a plan a canal Panama"
println("'$text' is palindrome: ${text.isPalindrome()}")
println("Word count: ${text.wordCount}")
val numbers = listOf(1, 2, 3, 4, 5)
println("Second element: ${numbers.secondOrNull()}")
}扩展的作用域
kotlin
class Host(val hostname: String) {
fun printHostname() { print(hostname) }
}
class Connection(val host: Host, val port: Int) {
fun printPort() { print(port) }
fun Host.printConnectionString() {
printHostname() // 调用Host.printHostname()
print(":")
printPort() // 调用Connection.printPort()
}
fun connect() {
host.printConnectionString() // 调用扩展函数
}
}
fun main() {
Connection(Host("kotl.in"), 443).connect()
}委托
类委托
kotlin
interface Base {
fun print()
fun printMessage(message: String)
}
class BaseImpl(val x: Int) : Base {
override fun print() { println("BaseImpl: $x") }
override fun printMessage(message: String) { println("BaseImpl: $message") }
}
// 委托给另一个对象
class Derived(b: Base) : Base by b {
// 可以重写委托的方法
override fun printMessage(message: String) {
println("Derived: $message")
}
}
fun main() {
val base = BaseImpl(42)
val derived = Derived(base)
derived.print() // 委托给BaseImpl
derived.printMessage("Hello") // 使用重写的方法
}最佳实践
1. 包组织
kotlin
// 按功能而非技术层面组织包
// 好的组织方式
com.example.ecommerce/
├── user/
├── product/
├── order/
└── payment/
// 避免的组织方式
com.example.ecommerce/
├── controllers/
├── services/
├── repositories/
└── models/2. 类设计
kotlin
// 优先使用数据类
data class User(val id: Long, val name: String, val email: String)
// 使用密封类表示状态
sealed class LoadingState {
object Loading : LoadingState()
data class Success(val data: String) : LoadingState()
data class Error(val message: String) : LoadingState()
}
// 使用对象声明实现单例
object ConfigManager {
fun getConfig(key: String): String? = TODO()
}3. 可见性
kotlin
class ApiClient {
// 公开必要的接口
fun fetchData(): String = processRequest()
// 隐藏实现细节
private fun processRequest(): String = TODO()
// 使用internal限制模块内访问
internal fun debugInfo(): String = TODO()
}下一步
了解了程序结构后,让我们深入学习Kotlin的数据类型系统。
下一章: 数据类型
练习题
- 创建一个包含多个包的项目结构
- 实现一个使用接口和实现类的图形绘制系统
- 设计一个使用密封类表示不同状态的网络请求结果
- 创建一个使用伴生对象的工厂模式示例
- 实现一个使用扩展函数增强现有类功能的工具库