侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现一个不可变的Person类并解释设计选择

2025-12-12 / 0 评论 / 6 阅读

题目

实现一个不可变的Person类并解释设计选择

信息

  • 类型:问答
  • 难度:⭐⭐

考点

不可变类设计,Scala类定义,伴生对象应用,val与var的区别

快速回答

实现要点:

  • 使用class Person(val name: String, val age: Int)定义不可变类
  • 实现方法def isAdult: Boolean = age >= 18
  • 通过伴生对象提供工厂方法
  • 不可变设计的优点:线程安全、易于推理、适合函数式编程
## 解析

原理说明

在Scala中,不可变对象一旦创建,其状态就不能改变。这带来了诸多好处:

  • 线程安全:无需同步即可在多线程环境中共享
  • 易于推理:对象状态在创建后固定不变
  • 函数式编程友好:支持纯函数和无副作用编程
  • 安全的哈希键:可用作HashMap键而不会因状态改变导致问题

代码实现

// 主类定义
class Person(val name: String, val age: Int) {
  // 判断是否成年
  def isAdult: Boolean = age >= 18

  // 创建新实例的方法(保持不可变性)
  def withName(newName: String): Person = new Person(newName, age)
  def withAge(newAge: Int): Person = new Person(name, newAge)
}

// 伴生对象
object Person {
  // 工厂方法
  def apply(name: String, age: Int): Person = new Person(name, age)

  // 提取器用于模式匹配
  def unapply(p: Person): Option[(String, Int)] = Some((p.name, p.age))
}

最佳实践

  • 所有字段声明为val确保不可变性
  • 提供withXxx方法返回新实例而非修改状态
  • 使用伴生对象:
    • 实现apply工厂方法(支持Person("Alice", 30)创建)
    • 实现unapply支持模式匹配
  • 对于复杂对象,考虑使用case class(自动生成以上功能)

常见错误

  • 错误1:使用var定义字段
    // 错误示例
    class Person(var name: String, var age: Int) // 可变状态!
  • 错误2:暴露可变集合
    // 错误示例
    class Person(val hobbies: scala.collection.mutable.ListBuffer[String])
    应改为不可变集合:val hobbies: List[String]
  • 错误3:修改方法返回原实例
    // 错误示例
    def setAge(newAge: Int): Unit = { this.age = newAge }

扩展知识

  • case class替代方案
    case class Person(name: String, age: Int) {
      def isAdult: Boolean = age >= 18
    }
    自动获得:
    • 不可变字段
    • apply/unapply方法
    • equals/hashCode/toString实现
    • copy方法(替代withXxx)
  • 防御性拷贝:当包含可变对象时,应在构造函数和getter中进行拷贝
  • 性能考量:频繁创建新对象可能影响性能,可考虑结构共享技术