Android sealed class result

Запечатанные классы (sealed)

Добавление модификатора sealed к суперклассу ограничивает возможность создания подклассов. Все прямые подклассы должны быть вложены в суперкласс. Запечатанный класс не может иметь наследников, объявленных вне класса.

В методе eval() при использовании when не пришлось использовать ветку else, так как sealed позволяет указать все доступные варианты и значение по умолчанию не требуется.

Если позже вы добавите новый подкласс, то выражение when будет ругаться и вы быстро вспомните, что нужно добавить новый код в программу.

По умолчанию запечатанный класс открыт и модификатор open не требуется. Запечатанные классы немного напоминают enum.

Пример: Продам кота дёшево

Создадим запечатанный класс AcceptedCurrency и три подкласса на его основе. Обратите внимание, что сейчас Kotlin разрешает объявлять подклассы не внутри запечатанного класса, а на одном уровне (для сравнения смотри старые примеры выше).

В классе активности создадим список принимаемых валют для покупки котят и применим его к адаптеру выпадающего списка.

Если запустить пример прямо сейчас, то в выпадающем списке увидим служебную информацию о классах. Не совсем то, что мы хотели увидеть.

Внесём изменения в запечатанный класс, чтобы у него появилось новое свойство.

Если вы пропустите какой-то подкласс в выражении when, то компилятор будет ругаться. Это удобно, когда вы будете вносить изменения в код.

Поменяем код для адаптера.

Теперь названия выводятся нормально.

Установим зависимость валют от рубля. Создадим в запечатанном классе абстрактное свойство valueInRubels. После этого студия потребует дополнить код у всех подклассов.

Добавим в класс ещё одну переменную ammount и функцию для подсчёта общей суммы.

Напишем код для щелчка кнопки. Вам нужно ввести минимальную и максимальную цену в любой валюте для одного котёнка, а кнопка покажет цену в рублях. Если вы увидите, что покупатель из Америки, то выставляете ценник в долларах. Если покупатель из непонятной страны, то ставьте тугрики (какая вам разница?).

В примере мы выставили цену от 2 до 3 долларов за котёнка (что-то мы продешевили) и сразу видим, сколько заработаем в рублях.

Источник

Kotlin. Изолированные (запечатанные) классы (sealed classes).

Изолированный класс — это еще одно новшество в языке Kotlin, которого не было в Java. Тем не менее само по себе понятие в программировании не является новым, Kotlin позаимствовал его у других языков.

В официальной документации изолированному классу было дано такое определение: класс, который позволяет ограничить иерархию классов конкретным множеством подтипов, каждый из которых может определять собственные свойства и функции. На мой взгляд формулировка не особо понятна.

Если говорить проще, то это абстрактный класс, который содержит в себе другие классы. По концепции очень похоже на enum , но с суперсилой. Выражена эта суперсила в том, что позволяет высвободиться от минусов enum . А именно:

  • В enum каждое значение — это константа, которая существует в единственном экземпляре. Значение константы нельзя подстроить под конкретную ситуацию, потому что при изменении значения в одном месте, оно измениться везде. В изолированном же классе можно создать столько подклассов, сколько необходимо для покрытия каждой ситуации. Помимо этого каждый подкласс может иметь несколько экземпляров, каждый из которых будет нести в себе свое собственное состояние.
  • Каждое значение в enum должно содержать одинаковый набор свойств. Не получится какому-либо значению задать дополнительное свойство. Напротив, каждый подкласс изолированного класса имеет свой конструктор со своими индивидуальными свойствами.

Для определения изолированного класса используется ключевое слово sealed .

В данном примере класс MessageType является изолированным. У него есть два подкласса-наследника — Success() и Failure() , каждый из которых имеет индивидуальный набор свойств. Тут может возникнуть вопрос: как Success() и Failure() могут наследоваться от MessageType() , если он не отмечен ключевым словом open ? Всё просто: изолированный класс “открыт” для наследования по умолчанию и дополнительно указывать слово open не требуется.

Также обратите внимание, что несмотря на то, что изолированный класс может иметь наследников, все они должны быть перечислены в одном с ним файле. Однако классы, которые расширяют наследников изолированного класса могут находиться где угодно.

Помимо этого, изолированный класс абстрактен по умолчанию и может содержать в себе абстрактные компоненты.

Изолированный класс можно использовать совместно с условным выражением when , при этом указывать ветку else не требуется.

На данный момент об изолированных классах сказать больше нечего. Поэтому резюмируем:

  • Изолированные классы — это enum с суперсилой.
  • У изолированного класса могут быть наследники, но все они должны находиться в одном файле с изолированным классом. Классы, которые расширяют наследников изолированного класса могут находиться где угодно.
  • Изолированные классы абстрактны и могут содержать в себе абстрактные компоненты.
  • Конструктор изолированного класса всегда приватен и это нельзя изменить.
  • Изолированные классы нельзя инициализировать.
  • Наследники изолированного класса могут быть классами любого типа: классом данных, объектом, обычным классом или даже другим изолированным классом.
Читайте также:  Svg image in android

Полезные ссылки

Sealed Classes — официальная документация.
Изолированные классы — перевод на русский.

Источник

Sealed with a class

Kotlin Vocabulary — Sealed Classes

Often we need to represent a limited set of possibilities; a web request either succeeds or fails, a User can only be a Pro-User or a standard user.

To model this we could use an enum , but this carries a number of limitations. Enum classes only allow a single instance of each value and can’t encode more information on each type, e.g. an Error case having an associated Exception property.

You could use an abstract class and a number of extensions but this loses the restricted set of types advantage brought by enums. Sealed classes provide the best of both worlds: the freedom of representation of abstract classes and the restricted set of types of enums. Read on to find out more about sealed classes or, if you prefer a video, check it out here:

The basics of sealed classes

Like abstract classes, sealed classes allow you to represent hierarchies. The child classes can be any type of class: a data class, an object, a regular class or even another sealed class. Unlike abstract classes, you have to define these hierarchies in the same file or as nested classes.

Trying to extend the sealed class outside the file it was defined in yields a compile error:

Forgetting a branch?

Often we want to handle all possible types:

But what if someone adds a new type of Result : InProgress :

Rather than relying on our memory or an IDE search to ensure that all when usages handle the new class the compiler can give us an error if a branch isn’t covered. when, like the if statement, only requires us to cover all options (i.e. to be exhaustive) by producing a compiler error when it’s used as an expression:

When expression must be exhaustive, add necessary ‘is InProgress’ branch or else branch instead

To get this nifty benefit even when we’re using when as a statement, add this helper extension property:

So now, by adding .exhaustive , if a branch is missing, the compiler will give us the same error we saw previously.

IDE auto-complete

As all sub-types of a sealed class are known, the IDE can fill all possible branches of a when statement for us:

This feature really shines with more complex sealed classes hierarchies as the IDE can recognise all branches:

This is the type of functionality that can’t be implemented with abstract classes as the compiler doesn’t know the inheritance hierarchy; therefore the IDE can’t generate the branches.

Under the hood

So what makes sealed classes behave as they do? Let’s see what’s going on in the decompiled Java code:

The metadata of the sealed class keeps the list of the child classes, allowing the compiler to use this information where needed.

The Result is implemented as an abstract class with two constructors:

  • A private default constructor
  • A synthetic constructor that can only be used by the Kotlin compiler

So, this means that no other class can directly call the constructor. If we look at the decompiled code of the Success class, we see that it calls through to the synthetic constructor:

Start using sealed classes to model restricted class hierarchies allowing the compiler and IDE to help you avoid type errors.

Источник

Android RecyclerView с использованием котлиновских sealed классов

RecyclerView — это один из самых лучших инструментов для отображения больших списков на Android. Как разработчики, вы, скорее всего понимаете о чем я говорю. У нас есть много дополнительных фич, таких как шаблоны вью холдеров, сложная анимация, Diff-Utils колбек для повышения производительности и т. д. Такие приложения, как WhatsApp и Gmail, используют RecyclerView для отображения бесконечного количества сообщений.

Одна из важнейших фич RecyclerView , которые я использую, — это типы представлений (view types). В RecyclerView мы можем отобразить несколько типов представлений. Раньше разработчики делали это с помощью флага типа представления в модели списка, который возвращали в функции getViewType адаптера RecyclerView .

Почему sealed классы Kotlin?

После появления Kotlin для разработки приложений под Android наши подходы к реализации кода кардинально изменились. То есть такие фичи, как расширения, почти заменили потребность в поддержании базовых классов для компонентов Android. Делегаты Kotlin внесли изменения в нашу работу с сеттерами и геттерами.

Читайте также:  Андроид пишет есть смс

Теперь пришло время обновлений в работе адаптера RecyclerView . Sealed классы из Kotlin оказывают значительное влияние на управление состояниями. Подробнее прочитать об этом вы можете в этой статье.

Вдохновившись этой статьей, я хочу показать вам реализацию типов представлений в RecyclerView с использованием sealed классов. Мы постараемся развить сравнение случайных чисел или лейаутов до типов классов. Если вы фанат Kotlin, я уверен, что вам понравится эта реализация.

Создание sealed классов в Kotlin

Первое, что нам нужно сделать при этом подходе — это создать все классы данных, которые мы намерены использовать в адаптере, а затем необходимо связать их в sealed классе. Давайте создадим группу классов данных:

Это несколько классов данных, которые я хотел отобразить в списке, основываясь на данных с серверов. Вы можете создать столько классов данных, сколько захотите. Этот подход хорошо масштабируется.

То, что мы можем работать с состояниями загрузки, хедерами, футерами и многим другое без написания дополнительных классов — это одно из крутых преимуществ данного метода. Вы скоро узнаете, как это сделать. Следующим шагом является создание sealed классов, содержащих все необходимые классы данных:

Sealed класс с пользовательскими моделями

Как я упоминал ранее, мы можем без дополнительных сложностей добавлять хидеры и футеры из RecyclerView , используя объект Kotlin:

Sealed класс с хидером и футером

На этом этапе заканчивается реализация нашего sealed класса.

Создание адаптера RecyclerView

После того, как мы разобрались с sealed классом, пришло время создать адаптер RecyclerView с UIModel списком. Это простой RecyclerView , но с sealed классом arraylist :

В приведенном выше коде показана базовая реализация адаптера RecyclerView без какой-либо логики sealed классов. Как можно заметить, мы объявили sealed классы arraylist (UIModel). Следующим шагом является возврат соответствующего типа представления на основе позиции:

Сравнение модели sealed класса для получения типа представления

Теперь, когда мы успешно вернули правильный лейаут на основе модели sealed класса, нам нужно создать соответствующий ViewHolder в функции onCreateViewHolder на основе viewtype :

Создание вью холдера с учетом типа представления из sealed классов

Последний шаг — обновить вью холдер на основе текущих данных элемента, чтобы адаптер мог отображать данные в пользовательском интерфейсе. Поскольку у адаптера есть несколько представлений, мы должны классифицировать тип, а затем вызвать соответствующий ViewHolder :

После объединения всех частей кода, он выглядит так:

Финальная версия адаптера

На этом этапе мы закончили. Мы реализовали все необходимое. Вы можете создать инстанс адаптера в Activity/Fragment и присвоить его RecyclerView . Как только вы получите данные, вам нужно вызвать функцию submitData с ArrayList :

Публикация данных в адаптер RecyclerView

DiffCallback

«DiffUtil — это вспомогательный класс, который может вычислять разницу между двумя списками и выводить список операций обновления, который преобразует первый список во второй». — Android Developer

Реализация diffcallback не является обязательной, но она повысит производительность, если вы работаете с большими наборами данных. Итак, чтобы реализовать difCallback в нашем адаптере, нам нужно различать модели и сравнивать нужные переменные:

Она похожа на стандартную реализацию diffCallback , но нам необходимо разделять типы. Создав ее, свяжите ее с адаптером в конструкторе.

Это все. Надеюсь, эта статья была для вас полезной. Спасибо за внимание!

Всех желающих приглашаем на двухдневный онлайн-интенсив «Делаем мобильную мини-игру за 2 дня». За 2 дня вы сделаете мобильную версию PopIt на языке Kotlin. В приложении будет простая анимация, звук хлопка, вибрация, таймер как соревновательный элемент. Интенсив подойдет для тех, кто хочет попробовать себя в роли Android-разработчика.
>> РЕГИСТРАЦИЯ

Источник

Working with Kotlin Sealed Classes

Most of us have used the Enum types in our projects. But, what if we want to define different types of subclasses of the same parent type? Can we still go with an Enum class? Can we use a Sealed class? Does it have any benefit compared to the Enum class? What is a Sealed class after all? Let’s find it out in this article.

Welcome to our MindOrks write up on Sealed classes in Kotlin.

We have a video tutorial on this concept on our MindOrks youtube channel. You can check it out here.

Let’s understand the concept of Sealed classes by understanding its difference from the Enum classes with a use case. Let’s take a Result and let’s say there are only two types of Results: Success and Error .

So, Enum classes are helpful, but they have their limitations. For example, each subtype of the Enum class can be only a constant and it has no state. That is, what if instead of just one hardcoded «Error», there are different dynamic error messages(the states of the objects), it is not possible using Enum. Also, we cannot have different types of subclasses involved, which we will be seeing with Sealed classes in a while. Now, let’s talk about Why the Sealed class over the Enum in detail with the example.

Читайте также:  Mega облачное хранилище для андроид

Why Sealed Class over Enum?

Sealed classes give us the flexibility of having different types of subclasses and also containing the state. The important point to be noted here is the subclasses that are extending the Sealed classes should be either nested classes of the Sealed class or should be declared in the same file as that of the Sealed class. We will see it later in this blog.

  • Enum types are constants and hence, it is difficult to maintain different states of the instances.
  • For example, in the Enum class Result that is considered above, we are storing only the string values attached to the Enum. But what if in the Error case, we want to display the actual Exception that has caused the error. It is not possible with enums since Enum types cannot hold the state of the type.
  • Subclasses of a sealed class, as discussed, are either ordinary classes, data classes or sealed classes themselves and hence it is easy to contain the state of the subclass.

Let’s consider an example: Firstly, let’s define a Sealed class Employee . How do we do this? By adding the keyword “sealed” in front of the class

Now according to our use case, we need to have the two types of Employees:

  • Manager (Name, age, list of reporting employees)
  • SeniorDev (Name, age, projects)

So let’s create two data classes: Manager and SeniorDev with the required constructor parameters:

This is how we can have the state(name, age, and etc) in the sealed class which is not possible with enum. Now, let’s talk about the advantages of Sealed Class over the Abstract Class.

Why Sealed Class over Abstract Class?

Sealed classes are abstract by itself, and cannot be instantiated directly. So let’s take a pause here. If Sealed classes are abstract by default, why can’t we use an abstract class instead of a sealed class in the first place? Well, the catch here is an abstract class can have their hierarchies anywhere in the project, whereas a sealed class should contain all the hierarchies in the same file.

To elaborate on this, if we try to define the SeniorDev class extending the sealed Employee class in a different file, we will be getting a compile-time error. That is how a Sealed class provides a restricted number of hierarchies, thereby providing the flexibility of defining different child classes of the parent sealed class. Here, the child classes can be data classes, ordinary classes, objects (Singleton in Kotlin), or sealed classes themselves and hence, the state of the Sealed class instance can be accessed as per requirement, similar to how a normal class object can be accessed.

Another important advantage of using a sealed class over abstract class is that it helps the IDE to understand the different types involved and thereby helps the user in auto-filling and avoiding spell mistakes. For example:

We can take advantage of the auto-fill feature in this case. Usually when we use “when”, we have an option to auto-fill the different cases that can exist and since the IDE is aware of the different types of subclasses, there is no requirement to add an else case.

When we consider abstract classes, they allow defining hierarchies from various files in the project, and hence, the IDE cannot understand the different subclasses involved. Hence, the compiler throws an error stating that an else case should be mentioned. This is another benefit of using the Sealed class over the Abstract class.

We can see from the above image that there is a compiler error stating to add a necessary else branch since the parent Employee class was an abstract class and hence the IDE has no idea if all the hierarchies are covered or not. This is the limited hierarchy advantage of using a Sealed Class.

We can also apply the use of Sealed classes in different examples in the Android Project. Suppose you want to display different types of Result:

Here, we have a data class success object which contains the success Data and a data class Error object which contains the state of the error.

You can check out our video tutorial on this concept here

This way, Sealed classes help us to write clean and concise code! That’s all the information about Sealed classes and their usage in Kotlin.

Источник

Оцените статью