Как вызвать переопределенную функцию на суперинтерфейсе? - PullRequest
0 голосов
/ 26 сентября 2018
interface CrudRepo {
  fun save()
  fun saveAll()
}

interface CustomRepo : CrudRepo {
  fun validate()
  override fun save() {
    validate()
    saveAll() // can call saveAll, I need to call save on CrudRepo here
  }
}

CrudRepo имеет функцию сохранения, которая не выполняет проверку.Я решил написать свой собственный интерфейс, который расширяет CrudRepo и переопределяет метод сохранения.В моем собственном определении save я хочу проверить и затем вызвать метод save для CrudRepo.

Что мне попробовать?

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Я думаю, что ответ Zoes содержит все, что вам нужно знать о наследовании или переопределении save -метода.Если ваш CustomRepo не был бы интерфейсом, вы могли бы использовать делегирование , например:

class CustomRepo(private val repo : CrudRepo) : CrudRepo by repo {
  fun validate() {}
  override fun save() {
    validate()
    repo.save()
  }
}

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

Если вы действительно хотите сохранить свой пользовательский interface, тогда я бывероятно, сделайте что-то следующим образом:

interface ValidatedCrudRepo : CrudRepo {
  fun validate()
  /**
   * Ensures that [validate] is called before the actual [save].
   */
  override fun save()
}
class CustomRepo(private val repo : CrudRepo) : ValidatedCrudRepo, CrudRepo by repo {
  override fun validate() {}
  override fun save() {
    validate()
    repo.save()
  }
}

Так что, если кто-то использует ValidatedCrudRepo, это гарантирует, что validate должен быть вызван перед фактическим сохранением и фактически также задокументирован таким образом.

0 голосов
/ 26 сентября 2018

Если вы попытаетесь использовать super, вы получите сообщение об ошибке, что «абстрактный член не может быть доступен напрямую».Это относится к интерфейсам и классам;Вы не можете вызывать абстрактные методы без тела на super.Это означает, что это не компилируется:

interface CrudRepo {
    fun save()
    fun saveAll()
}

interface CustomRepo : CrudRepo {
    fun validate()
    override fun save() {
        validate()
        super.saveAll() 
    }
}

Но измените интерфейс CrudRepo на это:

interface CrudRepo {
    fun save()
    fun saveAll(){
    }

}

И это произойдет.

Если вы хотите абстрактный примервот, пожалуйста:

abstract class CrudRepo {
    abstract fun save()
    abstract fun saveAll()
}

class CustomRepo : CrudRepo() {
    override fun saveAll() { }
    override fun save() {
        super.saveAll() 
    }
}

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

interface CustomRepo : CrudRepo
class MyClass : CustomRepo

означает, что MyClass является дочерним по отношению к CrudRepo и CustomRepo.И MyClass() as CustomRepo, и MyClass() as CrudRepo будут компилироваться.

Теперь, что это значит для вашей проблемы?

В CrudRepo нет метода save с точки зрения CustomRepo.Он не реализован, и поэтому вы не можете вызвать его напрямую.Вызов super.saveAll(), как я показал выше, означает call the saveAll method on my parent.super - очень строгое ключевое слово.Однако saveAll() не переопределяется.Вы можете вызвать save, но вы не можете вызвать его на суперинтерфейсе, потому что суперинтерфейс не имеет метода сохранения с телом .Последние три слова этого предложения здесь невероятно важны;поскольку метод, определенный в интерфейсе CrudBody, не имеет тела, его нельзя вызвать.

И, кроме того, поскольку вы переопределили метод, любые обращения к нему могут привести к рекурсии.Если вы сделаете это:

override fun save(){
    save()
}

, он будет вызывать себя снова и снова, пока не произойдет сбой.См. Что такое StackOverflowError? .

Теперь, если у вас есть фактический класс:

class CustomRepoImpl : CustomRepo{
    override fun saveAll() {
    }

    override fun save() {
        super.save()
    }

    override fun validate() {
    }

}

обратите внимание, как он вызывает super;теперь он будет вызывать метод super в CustomRepo.Однако это не обязательно.

И когда вы переопределяете save в CustomRepo, помните одну вещь: вы переопределяете метод CrudRepo.Любые дочерние классы больше не обязаны переопределять его вообще.Пример реализации, который я имел, скомпилировался бы без него.Причина, по которой saveAll работает (без ключевого слова super), заключается в том, что он является абстрактным и не ссылается на метод, из которого он вызывается.Смотрите ссылку StackOverflowError.Если вы вызываете переопределенный метод, вызывается метод в дочернем классе, если только метод не вызывается на super.

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

TL; DR: Вы не можете вызвать супер метод абстрактного / безличного метода.saveAll относится к первой реализации метода или суперклассу, если он определен в дочернем элементе.Вызов save приведет к ошибке StackOverflowError.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...