用单个类和枚举参数替换接口或抽象类(Kotlin)

时间:2018-11-02 00:03:25

标签: oop generics kotlin

我想用一个enum参数调用一个类,并让Typescollections<Type>的类成员取决于此enum参数。我愿意接受一个答案,那就是这正是抽象类和接口的目的,没有其他方法可以按照这些原则进行操作。我只是想确保我没有错过任何聪明的把戏。

例如,我想将电影帧的集合表示为字节数组或短裤数组,其中图像处理取决于颜色的通道深度和位深度。我相信标准做法是创建一个抽象类或接口,然后从每个enum成员的类或接口继承。此标准解决方案需要多个文件,并将处理细节分成这些单独的文件。

以下类说明了没有接口或抽象类的尝试。问题在于,进入或退出此类的任何内容都具有类型Any,并且必须显式进行强制转换。那是一个初学者。我对泛型还不太熟悉,是否可以提供解决方案。 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 :(得分:0)

感谢您的建议和鼓励。从尤尼·吉布斯(Yoni Gibbs)的评论来看,“密封的类”是我寻求的“技巧”,即枚举和多态性的某种组合。关于泛型,花了两个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