На мой взгляд, это не лучший способ использования «объекта». Если вы хотите создать какую-то сессию, лучше использовать сопутствующий объект класса. Для более чистой архитектуры лучше создать фабрику сессий с (im) изменяемыми состояниями.
class LoginSession private constructor(
val variableA: String, // here you can also define default value
val variableB: String,
val variableC: String
) {
companion object {
fun create(a: String, b: String, c: String) = LoginSession(a, b, c)
}
}
Но, если вы настаиваете на том, что вам нужны синглтоны, вы можете изменить это решение следующим образом:
class LoginSession private constructor(
val variableA: String, // here you can also define default value
val variableB: String,
val variableC: String
) {
companion object {
var instance: LoginSession? = null
fun create(a: String, b: String, c: String) = if(instance != null) instance
else LoginSession(a, b, c).apply {
instance = this
}
fun reCreate(a: String, b: String, c: String): LoginSession? {
instance = null
return create(a, b, c)
}
}
}
Это решение может предоставить вам больше гибкости в вашем проекте, потому что вы можете манипулировать состоянием своего синглтона LoginSession по мере необходимости, без каких-либо последствий, таких как NPE или неправильные значения в var. Также, как мне кажется, этот код более чистый и масштабируемый.
U.P.D
Кроме того, я советую вам следовать рекомендациям Боба Мартина и Стива Макконнелла, в которых говорилось: «Если у вас есть более 2 аргументов в функциях / методах, попробуйте объединить их в 1 DTO (объект передачи данных)»
data class SessionDTO(val variableA: String, val variableB: String, val variableC: String)
class LoginSession private constructor(val session: SessionDTO) {
companion object {
var instance: LoginSession? = null
fun create(session: SessionDTO) = if(instance != null) instance
else LoginSession(session).apply {
instance = this
}
fun reCreate(session: SessionDTO): LoginSession? {
instance = null
return create(session)
}
}
}
Итак, в этом случае у вас есть некоторые преимущества:
- У вас есть неизменность без каких-либо побочных эффектов. Ваши данные имеют одно значение, доступное из любой части вашего приложения. Попробуйте использовать больше неизменяемости, как вы можете. Если одно из полей в SessionDTO изменится, вам придется заново создать сеанс входа в систему. И это правильно, потому что состояние вашего объекта изменилось. Прочитайте https://www.elegantobjects.org/,, это многое объясняет.
- У вас есть гибкий и масштабируемый DTO, который вы можете изменить в любое время.
- У вас есть ручное управление состоянием LoginSession. У вас есть возможность создать / воссоздать / уничтожить его экземпляр. Объект Котлина не дает вам этой точки.
В заключение я бы сказал, что Объекты не являются серебряной пулей. Он предназначен для создания простых синглетонов. И, думая, как инженер, вы должны выбрать правильный путь между базовыми реализациями и более сложными шаблонами. Например, ИМХО, лучший способ использовать объект Котлина (я взял его из книги «Котлин в действии» и немного изменил):
object Payroll {
/*
it's mocked method, imagine that inside it called network request,
or request in database, or from local storage(json-file, xml-file)
or something like this.
*/
val employees: List<Employer>
get() = Storage.loadAllEmployees()
/*
So, you can in any time call method `calculateSalary` in any part
of your application, and calculation algorithm will
evaluate salary for all current employers in system.
*/
fun calculateSalary() {
for(person in employees) {
// some evaluation algorithm
}
}
}