Замена интерфейса или абстрактного класса на отдельный класс и параметр Enum (Kotlin) - PullRequest
0 голосов
/ 02 ноября 2018

Я хотел бы вызвать один класс с параметром enum и позволить Types и collections<Type> членов класса зависеть от этого параметра enum. Я готов принять ответ, что в этом и заключается цель абстрактных классов и интерфейсов, и нет другого пути продвинуться в этом направлении. Я просто хочу быть уверен, что не пропустил хитрый трюк.

Например, я хотел представить коллекцию кадров фильма как массивы байтов или массивы шорт, где обработка изображения зависит от глубины цвета канала и битовой глубины. Я считаю, что стандартной практикой было бы создание абстрактного класса или интерфейса, а затем наследование от них для каждого из enum членов. Это стандартное решение требует нескольких файлов и разделяет особенности обработки на эти отдельные файлы.

Следующий класс иллюстрирует попытку без интерфейса или абстрактного класса. Проблема в том, что все, что входит или выходит из этого класса, имеет тип Any и должно быть явно приведено. Это не стартер. Я недостаточно знаком с Generics, чтобы понять, дает ли это решение. В JVM есть Type стирание, так что я думаю, что это тоже тупик. Мой пример - Kotlin, но я думаю, что он следует и для других объектно-ориентированных языков.

class MovieFrames(val nRow:Int,val nCol:Int, val type: ElementType) {
  val list = mutableListOf<Any>()
  val frameSize = nRow * nCol
  fun nframe() = list.size

  constructor(nRow: Int, nCol: Int, values: List<Any>, type: ElementType = ElementType.Gray8) :
        this(nRow, nCol, type) {
    when (type) {
        ElementType.RGB8 -> values.forEach { list.add(it as ByteArray) }
        ElementType.Gray8 -> values.forEach { list.add(it as ByteArray) }
        ElementType.Gray16 -> values.forEach { list.add(it as ShortArray) }
    }

  }

  fun saveToFile(filename: String) {
    when (type) {
        ElementType.RGB8 -> {/*put Red, Green, Blue bytes to disk*/ }
        ElementType.Gray8 -> {/*put Bytes to disk*/ }
        ElementType.Gray16 -> {/*put Bytes to disk with specific byte ordering*/ }
    }
  }

  fun getFrame(f:Int) : Any {
    return list[f]
    }
}

enum class ElementType(bitDepth: Int, channels: Int) {
  RGB8(8, 3),
  Gray8(8, 1),
  Gray16(16, 1);
}

1 Ответ

0 голосов
/ 04 ноября 2018

Спасибо за предложения и поддержку. Из комментария Йони Гиббса «Запечатанные классы» был «уловкой», которую я искал, это некоторая комбинация Enum и полиморфизма. Что касается Generics, потребовалось два Types для инкапсуляции нижележащего объекта хранения и того, как представлены пиксели. Вот результат, который объединяет все предложения.

//e.g. T=ByteArray, ShortArray
//e.g. E=Byte,Short
sealed class Frames<T,E>(val nrow:Int,val ncol:Int,val bitDepth:Int,val channelDepth:Int) {
  val size=nrow*ncol //frame size
  abstract val list:MutableList<T>
  fun totalBytes() = list.size*size*bitDepth/8*channelDepth
  abstract fun set(i:Int,data:E)
  abstract fun get(i:Int): E

  fun saveToDisk(filename:String)=saveByteArray(filename,toByteArray())
    abstract fun toByteArray(isSmallEndian:Boolean=false):ByteArray
  }

class Gray8Frame(nrow:Int,ncol:Int) :
    Frames<ByteArray,Byte>(nrow,ncol,8,1) {
  override val list= mutableListOf<ByteArray>()
  override fun set(i: Int,data:Byte) {list[i/size][i%size]=data}
  override fun get(i: Int)=list[i/size][i%size]
  override fun toByteArray(isSmallEndian: Boolean)
        = ByteArray(totalBytes()){get(it)}
}
class Gray16Frame(nrow:Int,ncol:Int) :
    Frames<ShortArray,Short>(nrow,ncol,16,1) {
  override val list= mutableListOf<ShortArray>()
  override fun set(i: Int,data:Short) {list[i/size][i%size]=data}
  override fun get(i: Int)=list[i/size][i%size]
  override fun toByteArray(isSmallEndian: Boolean)
        = list.flatMap { it.toByteList() }.toByteArray() 
        //implement short-->List<Byte>
}

class RGBFrame(nrow:Int,ncol:Int) :
    Frames<ByteArray,List<Byte>>(nrow,ncol,8,3) {
  override val list= mutableListOf<ByteArray>()
  override fun set(i: Int,data:List<Byte>) {
    list[i/size][3*i%size+0]=data[0]//Red
    list[i/size][3*i%size+1]=data[1]//Green
    list[i/size][3*i%size+2]=data[2]//Blue
  }
  override fun get(i: Int)=listOf(
    list[i/size][3*i%size+0],//Red
    list[i/size][3*i%size+1],//Green
    list[i/size][3*i%size+2] //Blue
  )
  override fun toByteArray(isSmallEndian: Boolean)
        = list.flatMap { it.asList() }.toByteArray()
  }

fun saveByteArray(filename:String, byteArray: ByteArray) { } //save bytes here
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...