В Kotlin класс может реализовывать несколько интерфейсов. Это общеизвестно. Класс также может использовать делегирование для реализации многочисленных интерфейсов, где реализации происходят из любых делегированных объектов, переданных в конструктор. Например:
01
02
03
04
05
06
07
08
09
10
11
|
class GeneticExperiment(human: Human, animal: Animal) : Human by human, Animal by animal interface Human { fun eat() fun sleep() fun poop() } interface Animal { fun bite() } |
Этот странный класс наследует функциональность от объектов Human
и Animal
передаваемых в конструктор. Без делегирования любые функции на любом из интерфейсов должны быть записаны вручную внутри класса.
Важным моментом, который следует отметить, является тот факт, что Human
и Animal
не имеют общего родительского интерфейса.
Если у вас есть интерфейсы, выходящие из общего интерфейса, то будут возникать ошибки компиляции из-за конфликтующих реализаций делегированных объектов. Например, код:
01
02
03
04
05
06
07
08
09
10
11
12
|
class ShapeShifter(human: Human, weightLifter: WeightLifter) : Human by human, WeightLifter by weightLifter interface Human { fun eat() fun sleep() fun poop() } interface WeightLifter : Human { fun liftHeavyStuff() fun pose() } |
Приводит к ошибкам:
01
02
03
04
05
06
07
08
09
10
11
12
|
Delegation.kt: 80 : 1 : error: class 'ShapeShifter' must override public open fun eat(): Unit defined in dev.lankydan.ShapeShifter because it inherits many implementations of it class ShapeShifter(human: Human, weightLifter: WeightLifter) : Human by human, WeightLifter by weightLifter ^ Delegation.kt: 80 : 1 : error: class 'ShapeShifter' must override public open fun sleep(): Unit defined in dev.lankydan.ShapeShifter because it inherits many implementations of it class ShapeShifter(human: Human, weightLifter: WeightLifter) : Human by human, WeightLifter by weightLifter ^ Delegation.kt: 80 : 1 : error: class 'ShapeShifter' must override public open fun poop(): Unit defined in dev.lankydan.ShapeShifter because it inherits many implementations of it class ShapeShifter(human: Human, weightLifter: WeightLifter) : Human by human, WeightLifter by weightLifter ^ |
Как вы можете видеть из ошибок, класс ShapeShifter
не знает, какую делегированную реализацию взять. Ошибки компиляции должны быть устранены путем явного переопределения конфликтующих функций. Переопределив функции, вы можете решить, какую делегированную реализацию вы хотите использовать, или вы можете предоставить новую. Исправленная версия этого класса может выглядеть так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class ShapeShifter( private val human: Human, private val weightLifter: WeightLifter ) : Human by human, WeightLifter by weightLifter { override fun eat() { human.eat() } override fun sleep() { weightLifter.sleep() } override fun poop() { println( "?" ) } } interface Human { fun eat() fun sleep() fun poop() } interface WeightLifter : Human { fun liftHeavyStuff() fun pose() } |
Только функции, объявленные в интерфейсе Human
должны быть переопределены вручную
Сделав небольшой шаг назад отсюда. Класс, который реализует дочерний интерфейс и делегирует его функциональность дочернему родительскому интерфейсу, будет компилироваться, пока все дочерние функции реализованы. Формулировка была сложной. Пример должен помочь уточнить, что я пытаюсь сказать:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
class ShapeShifter(copied: Human) : WeightLifter, Human by copied { override fun liftHeavyStuff() { println( "?️♂️" ) } override fun pose() { println( "?" ) } } interface Human { fun eat() fun sleep() fun poop() } interface WeightLifter : Human { fun liftHeavyStuff() fun pose() } |
Только функции, объявленные в интерфейсе WeightLifter
необходимо добавлять вручную
Чтобы подвести итог:
- Класс может реализовывать несколько интерфейсов и делегировать свои функциональные возможности одному или нескольким объектам.
- Класс с несколькими интерфейсами, расширяющими общий родительский элемент, может делегировать реализацию каждого интерфейса, но должен переопределять функции, определенные в родительском элементе.
- Класс, который реализует дочерний интерфейс, может делегировать его родителю и должен только добавить функции, определенные в дочернем.
Опубликовано на Java Code Geeks с разрешения Дэна Ньютона, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Реализация нескольких интерфейсов через делегирование Мнения, высказанные участниками Java Code Geeks, являются их собственными. |