Как реализовать шаблон проектирования шаблонов в Котлине?

Рассмотрим проблему:

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

 abstract class Base { fun computeSomething(argument: Int): Int { require(argument > 0) // Some intricate checking return execute(argument) } // Pure functionality, assuming correct arguments // Ideally, this would be private. protected abstract fun execute(validArgument: Int): Int } class Derived1: Base() { override fun execute(validArgument: Int): Int = validArgument * validArgument } class Derived2: Base() { override fun execute(validArgument: Int): Int = validArgument * validArgument * validArgument } fun main(args: Array<String>) { val d = Derived1() println(d.computeSomething(23)) } 

Я хотел бы иметь Base::execute private, так что никакой подкласс Base может вызвать его случайно, не проверяя его аргументы. К сожалению, это невозможно:

Ошибка: (9, 5) Kotlin: Модификатор «private» несовместим с «абстрактным»

protected Kotlin лучше, чем protected Java, поскольку он делает функцию доступной только для подклассов, но тем не менее, идеальный случай будет private .

Итак, есть ли правильный способ реализовать этот шаблон? Кроме того, из любопытства, является несовместимость private и abstract преднамеренного выбора языкового дизайна?

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

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

  • Вы можете использовать лямбда и передать это конструктору Base
  • Вы можете создать реализацию интерфейса, которая обрабатывает логику выполнения

Передавая их классу Base в своем конструкторе, вы передаете свою собственность этому классу.

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

 abstract class Base { fun computeSomething(argument: Int): Int { return execute(ValueCheck(argument)) } protected abstract fun execute(validArgument: ValueCheck) protected class ValueCheck(a: Int) { private val value = checkValue(a) private fun checkValue(argument: Int): Int { require(argument > 0) return argument } fun get() = value } } 

и когда производный класс хотел бы вызвать execute, он должен передать объект, который проверяет значение при создании экземпляра

Intereting Posts
RX2.0 вложенная обработка ошибок подписки Различные целевые позиции при использовании разных размеров вида с помощью ObjectAnimator Неиспользуемые аргументы при уничтожении объекта в Котлине Ошибка: супертипы следующих классов не могут быть разрешены. Убедитесь, что у вас есть необходимые зависимости в пути к классам Как запустить тесты Spek с Maven? Использование RxJava для объединения локальных данных с удаленными (или кэшированными) данными Котлин: Разница в определении коллекции Android Retrofit + SimpleXmlConverter с пустой сущностью Kotlin – Почему эта функция не подходит для рекурсии хвоста? Kotlin отражают proguard SmallSortedMap поделиться текстом в студии android с помощью kotlin Kotlin загружает внешний класс? Как позволить классу данных реализовать интерфейс / расширяет свойства суперкласса в Котлине? Как сделать работу @Autowired в обычном классе? Ошибка стекирования потока при использовании факториала рекурсией на ктолине