Objetos Companion
Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 13 de 57.
Alguns membros pertencem à classe como um todo, em vez de pertencerem a uma única instância. O Kotlin os coloca em um companion object dentro da classe, e você os chama por meio do nome da classe:
class Temperature(val celsius: Double) {
companion object {
fun fromFahrenheit(f: Double) = Temperature((f - 32) * 5 / 9)
}
}Dentro de main:
val boiling = Temperature.fromFahrenheit(212.0)
println(boiling.celsius)Saída:
100.0fromFahrenheit é uma função de fábrica: uma função que cria instâncias. Diferentemente de um construtor, ela tem um nome descritivo e pode retornar null em vez de um objeto. Com um private constructor, a fábrica é a única forma de entrada, então ela pode verificar e limpar a entrada primeiro:
class Username private constructor(val text: String) {
companion object {
fun of(raw: String): Username? {
val clean = raw.trim().lowercase()
return if (clean.length in 3..12) Username(clean) else null
}
}
}Dentro de main:
println(Username.of(" Ada_L ")?.text)
println(Username.of("x")?.text)
// Username("x") // erro: o construtor é privadoSaída:
ada_l
nullO objeto companion pertence à classe, portanto pode chamar o construtor privado, e o próprio código da classe usa os membros do companion sem um prefixo. Aqui, cada ticket recebe o próximo número de um contador compartilhado por todos os tickets:
class Ticket(val holder: String) {
val number = nextNumber++
companion object {
private var nextNumber = 1
val issued: Int
get() = nextNumber - 1
}
}Dentro de main:
val a = Ticket("Ada")
val b = Ticket("Bo")
println("${a.holder} #${a.number}, ${b.holder} #${b.number}")
println("issued: ${Ticket.issued}")Saída:
Ada #1, Bo #2
issued: 2Kotlin não tem a palavra-chave static. Os membros do companion desempenham esse papel: uma cópia para toda a classe, acessada como ClassName.member. Como qualquer objeto, o companion é criado uma vez, quando a classe é usada pela primeira vez. Coloque nele o que não depende de uma instância, como fábricas e contadores compartilhados; tudo o que lê os dados de uma instância continua sendo um membro normal.
class User private constructor(val name: String) {
fun greet() = "hi $name" // precisa de uma instância: user.greet()
companion object {
fun guest() = User("guest") // pertence à classe: User.guest()
}
}Desafio
FácilComplete a classe Coupon. Seu construtor é privado, então os cupons são criados pela fábrica Coupon.create(code, percent) no objeto companion. Ela retorna null, a menos que o código tenha de 4 a 10 caracteres compostos por letras maiúsculas e dígitos e que o percentual esteja entre 1 e 90. O objeto companion também conta os cupons que criou em created, que o código externo pode ler, mas não alterar. apply(price) retorna o preço menos o desconto, arredondado para baixo (price * (100 - percent) / 100).
O código fornecido lê linhas SAVE10 10 200 (código, percentual, preço). Ele imprime SAVE10: 180 ou invalid coupon SAVE10 e, por fim, created: com a contagem.
Seu código deve ficar em Coupon.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
fun main() {
// Código de entrada/saída fornecido: mantenha-o como está
val input = generateSequence(::readLine).toList()
for (line in input) {
val (code, percent, price) = line.split(" ")
val coupon = Coupon.create(code, percent.toInt())
if (coupon == null) println("invalid coupon $code") else println("${coupon.code}: ${coupon.apply(price.toInt())}")
}
println("created: ${Coupon.created}")
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesConstrutores PrimáriosBlocos init e ValidaçãoConstrutores SecundáriosRecapitulação - Cartão da Biblioteca4Herança
Classes Abertas e SubclassesSobrescrevendo Membrossuper e ConstrutoresClasses AbstratasRevisão - Diretório de Funcionários2Propriedades e Encapsulamento
Acessores PersonalizadosModificadores de VisibilidadeSetters Privadoslazy e lateinitRevisão - Conta Bancária5Interfaces
Declarando InterfacesMétodos PadrãoMúltiplas InterfacesInterfaces como TiposRecapitulação - Métodos de Pagamento8Genéricos
Funções genéricasClasses genéricasRestrições de tipoVariância com in e outRecapitulação - Fila de prioridade11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de Livros3Objetos e Companheiros
Declarações de ObjetosObjetos CompanionConstantes com constExpressões de ObjetosRevisão - BilheteriaPratique por conta própria: Playground de Kotlin