Запечатани класове в Котлин

1. Въведение

Просто казано, езикът Kotlin заимства редица концепции от други функционални езици, за да помогне с писането на по-безопасен и по-четим код. Запечатаните йерархии е една от тези концепции.

2. Какво е запечатан клас?

Запечатаните класове ни позволяват да коригираме йерархии на типове и забраняваме на разработчиците да създават нови подкласове.

Те са полезни, когато имате много строга йерархия на наследяване, с определен набор от възможни подкласове и без други. Компилаторът гарантира, че само класове, дефинирани в същия файл с източник като запечатания клас, могат да наследяват от него.

Запечатаните класове също са имплицитно абстрактни . Те трябва да се третират като такива в останалата част от вашия код, с изключение на това, че нищо друго не е в състояние да ги приложи.

Запечатаните класове могат да имат дефинирани полета и методи, включително абстрактни и внедрени функции. Това означава, че можете да имате основно представяне на класа и след това да го коригирате според подкласовете.

3. Кога да се използват запечатани класове?

Запечатаните класове са предназначени да се използват, когато има много специфичен набор от възможни опции за стойност и когато всяка от тези опции е функционално различна - само алгебрични типове данни.

Често използваните случаи могат да включват внедряване на държавна машина или в монадично програмиране, което става все по-популярно с появата на концепции за функционално програмиране.

Всеки път, когато имате множество опции и те се различават само по смисъла на данните, може да е по-добре да използвате Enum Classes вместо това.

Винаги, когато имате неизвестен брой опции, не можете да използвате запечатан клас, защото това ще спре да добавяте опции извън оригиналния файл.

4. Писане на запечатани класове

Нека започнем с написването на собствен запечатан клас - добрият пример за такава запечатана йерархия е Незадължителен от Java 8 - който може да бъде или Някои, или Никой.

Когато прилагате това, има много смисъл да ограничите възможността за създаване на нови реализации - двете предоставени реализации са изчерпателни и никой не трябва да добавя свои собствени.

Като такива можем да приложим това:

sealed class Optional { // ... abstract fun isPresent(): Boolean } data class Some(val value: V) : Optional() { // ... override fun isPresent(): Boolean = true } class None : Optional() { // ... override fun isPresent(): Boolean = false }

Вече може да се гарантира, че всеки път, когато имате екземпляр на Незадължителен , всъщност имате или Някои, или Никой.

В Java 8 действителното изпълнение изглежда различно поради липсата на запечатани класове.

След това можем да използваме това в нашите изчисления:

val result: Optional = divide(1, 0) println(result.isPresent()) if (result is Some) { println(result.value) }

Първият ред ще върне Няколко или Няма . След това извеждаме дали имаме резултат или не.

5. Използвайте с кога

Kotlin има поддръжка за използване на запечатани класове в своите конструкции, когато . Тъй като винаги има точен набор от възможни подкласове, компилаторът може да ви предупреди, ако някой клон не се обработва, по абсолютно същия начин, както при изброяванията.

Това означава, че в такива ситуации обикновено няма нужда от манипулатор за обхващане, което от своя страна означава, че добавянето на нов подклас е автоматично безопасно - компилаторът веднага ще ви предупреди, ако не сте се справили с него, и ще ви трябва за да поправите такива грешки, преди да продължите.

Горният пример може да бъде разширен, за да изведе или резултата, или грешка в зависимост от върнатия тип:

val message = when (result) { is Some -> "Answer: ${result.value}" is None -> "No result" } println(message)

Ако някой от двата клона липсва, това няма да се компилира и вместо това ще доведе до грешка на:

'when' expression must be exhaustive, add necessary 'else' branch

6. Обобщение

Запечатаните класове могат да бъдат безценен инструмент за вашата кутия с инструменти за проектиране на API. Разрешаването на добре позната, структурирана йерархия на класове, която някога може да бъде един от очаквания набор от класове, може да помогне за премахването на цял набор от потенциални условия за грешки от вашия код, като същевременно прави нещата лесни за четене и поддръжка.

Както винаги, кодови фрагменти могат да бъдат намерени в GitHub.