Как создать внутренний класс, где только внешний класс может получить доступ к конструктору, а остальное видно везде? - PullRequest
0 голосов
/ 16 января 2019

Изначально я хотел создать класс, который может прервать создание экземпляров в конструкторе, но согласно этой ссылке вместо этого я должен использовать класс Factory. Но теперь я хочу запретить кому-либо, кроме класса фабрики, создавать объект класса "Inner", предоставляя каждому доступ к методам внутреннего класса.

Я уже попробовал этот ответ .

import java.util.Date

object InnerFactory {

    class Inner private constructor(startDate: Date? = null, endDate: Date? = null) {
        fun getTimeDifference(): Long? {
            //calculates time difference but doesn't matter to this example
        }
    }

    fun createInnerObject(startDate: Date? = null, endDate: Date? = null): Inner? {
        if (startDate != null && endDate != null && !endDate.after(startDate)) {
            return null
        }

        return Inner(startDate, endDate)
    }

}

Я бы использовал его следующим образом:

val date1 = Date(1547600000)
val date2 = Date(1547600600)
val inner = InnerFactory.createInnerObject(date1, date2) //should return an instance
val invalidInner = InnerFactory.createInnerObject(date2, date1) //should not return an instance because the "endDate" is before "startDate"
val difference = inner?.getTimeDifference()

Он говорит «не может получить доступ» : он закрыт для «Inner» при наведении указателя мыши на использование конструктора в функции «createInnerObject».

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Что вы могли бы сделать:

  • представляет interface Inner со всеми необходимыми функциями, которые должны быть доступны
  • сделать все классы private и реализовать этот интерфейс

Пример:

object InnerFactory {

  interface Inner {
    fun getTimeDifference(): Long?
  }

  private class InnerImpl(startDate: Date? = null, endDate: Date? = null) : Inner {
    override fun getTimeDifference(): Long? = TODO("some implementation")
  }


  fun createInnerObject(startDate: Date? = null, endDate: Date? = null): Inner? {
    if (startDate != null && endDate != null && !endDate.after(startDate)) {
      return null
    }
    return InnerImpl(startDate, endDate) // InnerImpl accessible from here but not from outside of InnerFactory...
  }
}

Теперь вы больше не можете получить доступ к InnerImpl извне, но все еще есть все необходимые функции:

// the following all work as it deals with the interface
val inner = InnerFactory.createInnerObject(date1, date2) //should return an instance
val invalidInner = InnerFactory.createInnerObject(date2, date1) //should not return an instance because the "endDate" is before "startDate"
val difference = inner?.getTimeDifference()

// the following will not compile:
InnerImpl()
0 голосов
/ 17 января 2019

Вы можете сделать constructor protected. Таким образом, вы только выставляете его на подклассы, в данном случае PrivateClass. Затем вы создадите экземпляр PrivateClass или null, но вернете его как InnerClass?.

object InnerFactory {

    fun createInnerObject(startDate: Date? = null, endDate: Date? = null): Inner? {
        // return null here if conditions are not met
        return PrivateClass(startDate, endDate)
    }

    open class Inner protected constructor(val startDate: Date?, val endDate: Date?) {
        fun getTimeDifference(): Long? { /* ... */ }
    }

    private class PrivateClass(startDate: Date?, endDate: Date?): Inner(startDate, endDate)
}
0 голосов
/ 16 января 2019

К сожалению, private члены внутренних классов Kotlin не доступны из внешнего экземпляра:

private означает видимый только внутри этого класса
Ссылка на Kotlin / Модификаторы видимости

Однако Java не имеет таких ограничений с помощью модификаторов видимости:

доступ разрешен, если и только если он происходит в теле типа верхнего уровня ( §7.6 ), которое включает в себя объявление члена или конструктора.
Спецификация языка Java / §6 Имена / §6.6 Контроль доступа / §6.6.1 Определение доступности

Это один из немногих (раздражающих) случаев, которые я обнаружил, когда правила Котлина делают общий шаблон Java невозможным.

Единственные обходные пути (, если , вы хотите сохранить текущую структуру), это переписать этот класс на Java или предоставить этому конструктору менее ограниченную видимость (например, internal.)

На форумах Kotlin было обсуждение - кажется, что это ограничение JVM, и что оно работает только в Java, потому что компилятор генерирует соответствующие synthetic средства доступа.

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