在Scala中隐藏继承的父案例类实现

时间:2019-04-10 15:32:15

标签: scala

这是一个非常具体的要求,因此在深入研究代码之前,请允许我提出一个假设的案例。

假设您的表中有很多行是相同的-为了将一行与另一行区分开,我们希望可能添加一个随机数列,该列可以帮助防止数据倾斜。例如:

--------------------------
|         MyClass1       |
--------------------------
| value1 | value2 | skew |
--------------------------
|   4    |   6    | 4962 |
--------------------------
|   4    |   6    | 6510 |
--------------------------
|   500  |   700  | 0    |
--------------------------
|   500  |   700  | 0    |
--------------------------

在这种情况下,偏斜有助于防止将数据聚集到一个位置。

一个人可以做以下事情:

case class MyClass1(value1: Int, value2: Int, skew: Int)

和偏斜的实例化将留给调用者,即:

MyClass1(value1 = 4, value2 = 6, skew = ComplexFunc(value1, value2))

但是,假设我有很多需要该偏斜值的类。在这种情况下,为每个实现都容易出错,而且还要求调用者知道偏斜值。因此,我想像这样隐藏偏斜值及其实现:

case class SkewClass(skew: Int)
object SkewClass {
    def apply(skewCondition: Boolean) : SkewClass = {
       if (skewCondition) SkewClass(RandomInt()) else SkewClass(0)
    }
}

case class MyClass1 extends SkewClass(
    val value1 : Int = 0
    val value2 : Int = 0
    val skew : Int = this.apply(value1 != 500 && value2 != 700)
}

简而言之,我希望能够创建MyClass1实例,并在其末尾添加一个可能为随机的整数,称为“偏斜”。即:

scala> val x = MyClass1(value1 = 500, value2 = 700)
x: MyClass1 = MyClass1(500, 700, 0)

scala> val y = MyClass1(value1 = 52, value2 = 63)
y: MyClass1 = MyClass1(52, 63, 5347)

scala>

很显然,上面的代码无法编译(我对scala还是很陌生),但是有没有办法修改此代码以允许使用此随机整数?

4 个答案:

答案 0 :(得分:1)

在这种情况下,您希望所有结构共享属性Skew,但不必共享任何其他详细信息。最好的解决方案是在此处使用特征。

trait Skew {
  def skewCondition: Boolean
  lazy val skew: Int = if (skewCondition) RandomInt() else 0
}

case class AlwaysSkew(v1: Int, v2: Int) extends Skew {
  override val skewCondition: Boolean = true
}

case class ConditionalSkew(v1: Int, v2: Int) extends Skew {
  override val skewCondition: Boolean = (v1 != 500) && (v2 != 700)
}

val x = ConditionalSkew(500, 700)
val y = ConditionalSkew(1234,5678)
x.skew //0
y.skew //A random Int

答案 1 :(得分:1)

您不能使用从其他字段初始化的字段来创建 <StackPanel> <TextBlock Background="Lavender" FontSize="32" Text="1+2=3" Language="ar-EA" FlowDirection="RightToLeft"/> </StackPanel> ,但是可以使用类对象来执行此操作。从计算偏斜的函数开始:

case class

然后使用类对象创建它的实例:

def computeSkew(value1: Int, value2: Int) =
  if (value1 == 500 && value2 == 700) 0 else Random.nextInt()

另一种选择是通过扩展case class MyClass1 private(value1: Int, value2: Int, skew: Int) object MyClass1 { def apply(value1: Int, value2: Int): MyClass1 = MyClass1(value1, value2, computeSkew(value1, value2)) } 类来添加字段,但是具有相同Skewvalue1的对象将始终比较相等,因为value2不会包含在skew测试中。


如评论中所述,我不确定将equals添加到核心数据对象是否是解决重复问题的正确方法。最好在表中使用时将偏斜包装在对象周围,并保持原始数据不变。

一个简单的包装看起来像这样:

skew

然后在表中使用case class WithSkew[T] private(data: T, skew: Int) object WithSkew { def apply[T](data: T): WithSkew[T] = WithSkew(data, Random.nextInt()) } val x = MyClass1(500, 700) val xSkew = WithSkew(x) 避免重复,并在再次从表中取出行时提取xSkew字段。


以前的版本不基于datavalue1执行自定义偏斜计算。这可以通过引入类型类来解决,以提供特定类的偏斜计算:

value2

除非该类存在trait HasSkew[T] { def skew(instance: T): Int } case class DefaultSkew[T]() extends HasSkew[T] { def skew(instance: T): Int = Random.nextInt() } object HasSkew { implicit object skew1 extends HasSkew[MyClass1] { def skew(data: MyClass1): Int = computeSkew(data.value1, data.value2) } } case class WithSkew[T] private(data: T, skew: Int) object WithSkew { def apply[T](data: T)(implicit sk: HasSkew[T] = DefaultSkew[T]()): WithSkew[T] = WithSkew(data, sk.skew(data)) } 的隐式实例,否则WithSkew包装器将使用DefaultSkew中的偏斜计算。

此版本具有更多样板代码,但是它将允许使用HasSkew值包装任何类,并且可以根据需要为每个特定类量身定制偏斜计算。

答案 2 :(得分:0)

我不确定您要在这里找到什么,但是根据您的描述,这就是我得到的:

class SkewedClass(values: Int*) {
    lazy val skew: Int = {
        values.sum * 1234
    }
}

case class MyClass1(value1: Int, value2: Int) extends SkewedClass(value1, value2)
case class MyClass2(value1: Int, value2: Int, value3: Int) extends SkewedClass(value1, value2, value3)

用您想使用的任何复杂函数替换偏斜实现。

答案 3 :(得分:0)

如果要隐藏倾斜的实现细节,可以使用自定义类型的scala。

trait SkewTrait {
   def skew: Int
}


// package MyClass1
sealed class SkewClass1(value1: Int, value2: Int) {
this: SkewTrait =>
override def skew: Int = if (value1 == 500 && value2 == 700) 3 else 0
}

case class MyClass1(value1:Int, value2: Int) extends SkewClass1(value1, value2) with SkewTrait


// package MyClass2
sealed class SkewClass2(value1: Int) {
   this: SkewTrait =>
   override def skew: Int = if (value1 == 300) 4 else 0
}

case class MyClass2(value1: Int, value2: Int) extends SkewClass2(value1) with SkewTrait


println(MyClass1(1,2).skew)
println(MyClass2(300,5).skew)

结果:

0
4