Как сделать публичный геттер и приватный сеттер для свойства в Kotlin?
Решение: явное указание видимости сеттера
В Kotlin вы можете указать модификатор доступа отдельно для сеттера, используя синтаксис private set после объявления свойства. При этом геттер по умолчанию остаётся публичным. Вот правильный код:
class User(name: String) {
var name: String = name
private set // сеттер приватный, геттер публичный
fun updateName(newName: String) {
// Внутри класса можно менять name
name = newName
}
}
fun main() {
val user = User("Alice")
println(user.name) // ✅ Читать можно (геттер публичный)
// user.name = "Bob" // ❌ Ошибка компиляции: сеттер приватный
user.updateName("Bob") // ✅ Изменение через метод класса
println(user.name) // Bob
}
Как это работает
Ключевое слово set после объявления свойства позволяет переопределить сеттер. Если вы пишете private set, то сеттер становится приватным, а геттер остаётся с той же видимостью, что и само свойство (по умолчанию — public). Также можно указать protected set или internal set.
Вариант с конструктором класса
Если свойство объявлено в первичном конструкторе, синтаксис немного меняется — нужно использовать private set внутри тела класса:
class User(private var name: String) {
// В конструкторе name — приватное свойство (и геттер, и сеттер приватные)
// Чтобы сделать геттер публичным, нужно объявить отдельное свойство
var publicName: String = name
private set
fun updateName(newName: String) {
name = newName
publicName = newName // синхронизация
}
}
// Или более элегантный вариант:
class User(name: String) {
var name: String = name
private set
}
Почему это лучше, чем в Java
В Kotlin не нужно писать отдельные методы getName() и setName(). Всё делается через свойства с контролем доступа. Это сокращает код и делает его более читаемым. Вы также можете добавить кастомную логику в геттер или сеттер:
var age: Int = 0
private set
get() = field // можно добавить валидацию или вычисления
// Пример с кастомным сеттером (приватным)
var score: Int = 0
private set(value) {
if (value >= 0) {
field = value
}
}
Важное замечание
Если вы используете private set с var, то свойство всё равно можно изменять внутри класса (включая методы, конструкторы и инициализаторы). Снаружи — только читать. Это идеально подходит для инкапсуляции, когда внешний код не должен напрямую менять значение, но может его получать.
Альтернативный подход: использование backing-свойства
Иногда проще и нагляднее использовать отдельное приватное свойство для хранения данных, а публичное — для чтения. Это особенно полезно, если нужно добавить валидацию или трансформацию при чтении:
class User(name: String) {
private var _name: String = name // приватное хранилище
var name: String = _name // публичное свойство только для чтения
private set // сеттер приватный, но мы его не используем
fun updateName(newName: String) {
// Валидация или другая логика
_name = newName
// name = newName // тоже сработает, но лучше напрямую через _name
}
}
// Или ещё проще — сделать name только для чтения (val):
class User(name: String) {
val name: String = name // публичный геттер, сеттера нет вообще
// Теперь name можно установить только в конструкторе
}
Когда использовать
Если вам нужно, чтобы свойство никогда не менялось после создания объекта — используйте val. Если же оно может меняться внутри класса, но не снаружи — var с private set — идеальный выбор. Backing-свойство (_name) оправдано, когда логика геттера или сеттера сложнее, чем простое присваивание.
Ответов пока нет.
Войдите чтобы оставить ответ