Clases
## Objetivos de Aprendizaje
- Dominar definiciones de clases
- Trabajar con constructores
- Comprender objetos companion
- Aprender case classes
- Dominar conceptos basicos de OOP en Scala
## Basicos de Clases
### Definiendo una Clase
```scala
class Person {
var name: String = ""
var age: Int = 0
def greet(): String = s"Hello, I'm $name"
}
val person = new Person()
person.name = "Alice"
person.age = 30
println(person.greet()) // Hello, I'm Alice
```
### Constructor Primario
Los parametros de clase se convierten en el constructor primario:
```scala
class Person(val name: String, var age: Int) {
def greet(): String = s"Hello, I'm $name"
}
val alice = new Person("Alice", 30)
println(alice.name) // Alice
println(alice.age) // 30
alice.age = 31 // OK - var
// alice.name = "Bob" // Error - val
```
### Constructor con Valores por Defecto
```scala
class Person(val name: String = "Unknown", var age: Int = 0) {
def greet(): String = s"Hello, I'm $name"
}
val unknown = new Person() // name="Unknown", age=0
val bob = new Person("Bob") // name="Bob", age=0
val alice = new Person("Alice", 30) // name="Alice", age=30
```
## Constructores Auxiliares
```scala
class Person(val name: String, var age: Int) {
def this(name: String) = this(name, 0) // Constructor auxiliar
def this() = this("Unknown", 0) // Otro auxiliar
override def toString = s"Person($name, $age)"
}
val p1 = new Person("Alice", 30)
val p2 = new Person("Bob")
val p3 = new Person()
```
## Modificadores de Visibilidad
### Miembros Privados
```scala
class BankAccount(private var balance: Double) {
def deposit(amount: Double): Unit = {
if (amount > 0) balance += amount
}
def withdraw(amount: Double): Boolean = {
if (amount > 0 && amount <= balance) {
balance -= amount
true
} else {
false
}
}
def getBalance: Double = balance // Getter
}
val account = new BankAccount(100)
account.deposit(50)
account.withdraw(30)
println(account.getBalance) // 120
// account.balance // Error: balance es privado
```
### Generacion de getter y setter
```scala
class Person {
var name: String = _ // Genera getter y setter
val id: Int = 0 // Solo genera getter
private var balance: Double = 0 // No se genera getter/setter
private[this] var secret: String = "" // Privado del objeto
}
```
## Objetos Companion
Un objeto companion tiene el mismo nombre que la clase:
```scala
class Person(val name: String, val age: Int) {
override def toString = s"Person($name, $age)"
}
object Person {
def apply(name: String, age: Int): Person = new Person(name, age)
def apply(name: String): Person = new Person(name, 0)
def createStudent(name: String, age: Int): Person = {
if (age < 0) throw new IllegalArgumentException("Invalid age")
new Person(name, age)
}
}
// Usando companion
val p1 = Person("Alice", 30) // metodo apply
val p2 = Person("Bob") // apply con edad por defecto
val p3 = Person.createStudent("Charlie", 25)
```
## Case Classes
Las case classes generan automaticamente:
- parametros val (campos inmutables)
- metodos apply, unapply, copy
- toString, equals, hashCode
```scala
case class Person(name: String, age: Int) {
def greet(): String = s"Hello, I'm $name"
}
val alice = Person("Alice", 30)
// No se necesita 'new' - apply se genera
val bob = Person("Bob", 25)
// Inmutable - no var permitido por defecto
// alice.age = 31 // Error!
// Copia con modificaciones
val aliceOlder = alice.copy(age = 31)
// Emparejamiento de patrones
alice match {
case Person(n, a) => s"$n is $a years old"
}
// Igualdad
val alice2 = Person("Alice", 30)
alice == alice2 // true (equals generado)
// Uso en hash map
val people = Set(alice, alice2)
// Set contiene solo un Person("Alice", 30)
```
## Objects
Los objects son instancias singleton:
```scala
object Config {
val defaultTimeout = 30
val maxRetries = 3
def getSetting(key: String): String = {
// Cargar desde config
key match {
case "timeout" => defaultTimeout.toString
case "retries" => maxRetries.toString
case _ => "unknown"
}
}
}
println(Config.defaultTimeout) // 30
println(Config.getSetting("timeout")) // 30
```
## Clase vs Object vs Case Class
| Caracteristica | Clase | Object | Case Class |
|----------------|-------|--------|------------|
| Instanciacion | new | Instancia unica | new (o apply) |
| Parametros | var/val | N/A | val por defecto |
| Metodos | Si | Si | Si |
| extends | Si | Si | Si |
| equals/hashCode | Referencia | N/A | Generado |
| apply | No generado | Si | Generado |
| unapply | No generado | Si | Generado |
| copy | No generado | N/A | Generado |
## Clases Abstractas
```scala
abstract class Shape {
def area(): Double
def perimeter(): Double
}
class Circle(val radius: Double) extends Shape {
def area(): Double = Math.PI * radius * radius
def perimeter(): Double = 2 * Math.PI * radius
}
class Rectangle(val width: Double, val height: Double) extends Shape {
def area(): Double = width * height
def perimeter(): Double = 2 * (width + height)
}
```
## Clases Anidadas
```scala
class Outer {
class Inner {
def hello() = "Hello from Inner"
}
def createInner(): Inner = new Inner()
}
val outer = new Outer()
val inner = outer.createInner()
println(inner.hello())
```
## Estructuras Tipo Enum
```scala
object Color extends Enumeration {
val Red = Value
val Green = Value
val Blue = Value
val Yellow = Value("YELLOW")
}
import Color._
Red match {
case Red => "Red"
case Green => "Green"
case Blue => "Blue"
case _ => "Other"
}
```
## Resumen
- Las clases definen blueprints; los objects son instancias singleton
- Los parametros del constructor primario pueden ser val o var
- Los miembros privados ocultan detalles de implementacion
- Los objetos companion proporcionan metodos de fabrica y utilidades estilo estatico
- Las case classes generan automaticamente boilerplate para datos inmutables
- La copia de case class crea copias modificadas
- Las clases abstractas definen contratos para subclases
- Usa objects para funciones de utilidad y estado singleton
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →