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

Oop 用单个类和枚举参数(Kotlin)替换接口或抽象类,oop,generics,kotlin,Oop,Generics,Kotlin,我想用enum参数调用单个类,并让类成员的类型和集合取决于此enum参数。我愿意接受这样一个答案:这正是抽象类和接口的目的,没有其他方法可以沿着这条路线前进。我只是想确定我没有错过一个聪明的把戏 例如,我想将电影帧集合表示为字节数组或短片数组,其中图像处理取决于颜色的通道深度和位深度。我相信标准做法是创建一个抽象类或接口,然后为每个enum成员继承这些抽象类或接口。此标准解决方案需要多个文件,并将处理细节分离到这些单独的文件中 下面的类说明了不使用接口或抽象类的尝试。问题是,任何进入或退出此类的

我想用
enum
参数调用单个类,并让类成员的
类型和
集合取决于此
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);
}
class电影框架(val nRow:Int,val nCol:Int,val type:ElementType){
val list=mutableListOf()
val frameSize=nRow*nCol
fun nframe()=list.size
构造函数(nRow:Int,nCol:Int,value:List,type:ElementType=ElementType.Gray8):
此(nRow、nCol、类型){
何时(输入){
ElementType.RGB8->values.forEach{list.add(它作为ByteArray)}
ElementType.Gray8->values.forEach{list.add(作为ByteArray添加)}
ElementType.Gray16->values.forEach{list.add(它作为ShortArray)}
}
}
趣味saveToFile(文件名:String){
何时(输入){
ElementType.RGB8->{/*将红色、绿色和蓝色字节放入磁盘*/}
ElementType.Gray8->{/*将字节放入磁盘*/}
ElementType.Gray16->{/*按特定字节顺序将字节放入磁盘*/}
}
}
fun-getFrame(f:Int):任何{
返回列表[f]
}
}
枚举类ElementType(位深度:Int,通道:Int){
RGB8(8,3),
格雷8(8,1),
灰色16(16,1);
}

感谢您的建议和鼓励。根据Yoni Gibbs的评论,密封类是我正在寻找的“技巧”,即枚举和多态性的某种组合。关于泛型,需要两种
类型
来封装下划线存储对象以及像素的表示方式。下面是综合所有建议的结果

//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
//例如T=ByteArray,ShortArray
//e、 g.e=字节,短
密封类帧(val nrow:Int、val ncol:Int、val bitDepth:Int、val channelDepth:Int){
val size=nrow*ncol//帧大小
抽象值列表:可变列表
fun totalBytes()=列表。大小*大小*位深度/8*通道深度
抽象趣味集(i:Int,data:E)
抽象乐趣获取(i:Int):E
fun saveToDisk(文件名:String)=saveByteArray(文件名,toByteArray())
抽象数组(isSmallEndian:Boolean=false):ByteArray
}
类Gray8Frame(nrow:Int,ncol:Int):
帧(nrow,ncol,8,1){
override val list=mutableListOf()
覆盖乐趣集(i:Int,data:Byte){list[i/size][i%size]=data}
覆盖乐趣获取(i:Int)=列表[i/size][i%size]
重写数组(isSmallEndian:布尔值)
=字节数组(totalBytes()){get(it)}
}
类Gray16Frame(nrow:Int,ncol:Int):
帧(nrow,ncol,16,1){
override val list=mutableListOf()
覆盖乐趣集(i:Int,data:Short){list[i/size][i%size]=data}
覆盖乐趣获取(i:Int)=列表[i/size][i%size]
重写数组(isSmallEndian:布尔值)
=list.flatMap{it.toByteList()}.tobyterarray()
//实现短-->列表
}
类RGB帧(nrow:Int,ncol:Int):
帧(nrow,ncol,8,3){
override val list=mutableListOf()
覆盖乐趣集(i:Int,数据:List){
列表[i/size][3*i%size+0]=数据[0]//红色
列表[i/size][3*i%size+1]=数据[1]//绿色
列表[i/size][3*i%size+2]=数据[2]//蓝色
}
覆盖乐趣获取(i:Int)=列表(
列表[i/size][3*i%size+0],//红色
列表[i/size][3*i%size+1],//绿色
列表[i/size][3*i%size+2]//蓝色
)
重写数组(isSmallEndian:布尔值)
=list.flatMap{it.asList()}.toByteArray()
}
fun saveByteArray(文件名:String,byteArray:byteArray){}//在此处保存字节

枚举是对象。他们可以有行为。让枚举对象执行行为,而不是基于值(
时)执行行为。例如,枚举可以定义
create(…)
来处理构造逻辑
values.forEach{list.add(它作为ByteArray)}
,以及用于保存逻辑的
saveToFile(…)
。这种方法更面向对象,因为enum对象现在负责依赖于所述enum对象的行为。如果我误解了你的问题,请告诉我。这个问题不清楚,你使用的术语也不标准。要回答你的问题,需要重写你的代码,并教你相当多的知识。了解泛型、面向对象设计、应该对哪些操作负责,等等。否则,我们为你做的工作超出了问题的范围,基本上就是“重写这个,让它为我工作。”我认为文斯·埃米尔的解决方案也是我会做的。这是否为您提供了继续进行所需的足够信息?你可能需要考虑的其他东西,这是Kotlin所特有的,是使用的,这基本上是枚举的扩展。也许对于这种非特定的问题,也许是更好的视觉。JaysMnar在引用其他站点时,常常有助于指出这一点。