Originalmente quería crear una clase que pudiera abortar la creación de instancias en el constructor, pero de acuerdo con este enlace , debería usar una clase Factory. Pero ahora quiero evitar que nadie, excepto la clase de fábrica, cree un objeto de clase "Interior" mientras da acceso a los métodos de la clase interna a todos.
Ya probé esta respuesta .
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) } }Yo lo usaría como el siguiente:
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()Dice "no se puede acceder a '<init>': es privado en 'Inner'" al pasar el mouse sobre mi uso del constructor en la función "createInnerObject".
Lo que podrías hacer:
interface Inner con todas las funciones necesarias que deben ser expuestasprivate e implemente esa interfazMuestra:
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... } } Ahora ya no puede acceder a InnerImpl desde el exterior, pero aún tiene todas las funciones necesarias disponibles:
// 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()Desafortunadamente, los miembros private de las clases internas de Kotlin no son accesibles desde la instancia externa:
privatesignifica visible dentro de esta clase solamente
Referencia de Kotlin /Modificadores de visibilidad
Sin embargo, Java no es tan restrictivo con sus modificadores de visibilidad:
el acceso está permitido si y solo si ocurre dentro del cuerpo del tipo de nivel superior ( §7.6 ) que encierra la declaración del miembro o constructor.
Especificación del lenguaje Java / §6 Nombres / §6.6 Control de acceso / §6.6.1 Determinación de la accesibilidad
Este es uno de los únicos casos (molestos) que he encontrado donde las reglas de Kotlin hacen imposible un patrón común de Java.
Las únicas soluciones ( si desea mantener su estructura actual) serían reescribir esta clase en Java o exponer este constructor con una visibilidad menos restrictiva (por ejemplo, internal ).
Hubo una discusión sobre esto en los foros de Kotlin: parece que se trata de una limitación de JVM y que solo funciona en Java porque el compilador genera accesores synthetic apropiados.
Podrías hacer que el constructor esté protected . De esta manera, solo lo expone a las subclases, en este caso, PrivateClass . Luego, creará una instancia de PrivateClass o null pero la devolverá como 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) }