消除重复的代码,其唯一的区别是类型

时间:2017-05-23 20:21:01

标签: scala

我有两个结构等效的类对,唯一的区别是类型。我希望能够将V1V2K1K2合并。我控制了这四个类,但我无法修改takesDoublesOrLists - 它来自一个库。

class V1 (
    val a: Double,
    val b: Double,
    // ...
    val z: Double
)

class K1(v: V1) {
    def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}

class V2 (
    val a: List[Double],
    val b: List[Double],
    // ...
    val z: List[Double]
)

class K2(v: V2) {
    def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}

我尝试关注type class pattern,但收到的错误是重载的方法takesDoublesOrLists无法应用于我的类型参数。

修改

重载函数takesDoublesOrLists的签名顾名思义:

def takesDoublesOrLists(a: Double, b: Double, /* ..., */ z: Double): Something = /* ... */
def takesDoublesOrLists(a: List[Double], b: List[Double], /* ..., */ z: List[Double]): Something = /* ... */

2 个答案:

答案 0 :(得分:1)

我可以看到您如何合并 public class MainActivity extends Activity { private ViewPager mViewPager; MediaPlayer mp; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mViewPager= (ViewPager) findViewById(R.id.view_pager); ImageAdapter adapter = new ImageAdapter(this); mViewPager.setAdapter(adapter); final GestureDetector tapGestureDetector = new GestureDetector(this, new TapGestureListener()); mViewPager.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { tapGestureDetector.onTouchEvent(event); return false; } }); } private class TapGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapConfirmed(MotionEvent e) { if (mViewPager.getCurrentItem() == 0) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.aa); mp.start(); } } else if (mViewPager.getCurrentItem() == 1) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.bb); mp.start(); } } else if (mViewPager.getCurrentItem() == 2) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.cc); mp.start(); } } else if (mViewPager.getCurrentItem() == 3) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.dd); mp.start(); } } else if (mViewPager.getCurrentItem() == 4) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.ee); mp.start(); } } else if (mViewPager.getCurrentItem() == 5) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.ff); mp.start(); } } else if (mViewPager.getCurrentItem() == 6) { if(mp != null && mp.isPlaying()){ mp.pause(); }else{ mp = MediaPlayer.create(MainActivity.this, R.raw.gg); mp.start(); } } return super.onSingleTapConfirmed(e); } } } V1,但不能合并V2K1

K2

编辑:如果您的K1和K2类比您举例说明的更复杂,您可以使用特征来打破这种行为:

class V[T] (
  val a: T,
  val b: T
  // ...
  val z: T
)

class K1(v: V[Double]) {
  def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}

class K2(v: V[List[Double]]) {
  def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}

答案 1 :(得分:1)

  

我尝试了类型类模式,但是出现了一个错误,即重载方法takeDoublesOrLists无法应用于我的类型参数。

您没有显示您的尝试,但您不应该调用takesDoublesOrLists的重载版本,它应该是类型类的一部分(当然,您可以在调用现有版本时调用现有版本实施它,如果有理由不在那里移动实施):

sealed trait DoubleOrList[A] {
  def doIt(a: A, b: A, /* ..., */ z: A): Something
}

object DoubleOrList {
  implicit object DoubleIsDoubleOrList extends DoubleOrList[Double] {
    def doIt(a: Double, b: Double, /* ..., */ z: Double): Something = 
      SomeObject.takesDoublesOrLists(a, b, z)
  }
  implicit object ListIsDoubleOrList extends DoubleOrList[List[Double]] { 
    def doIt(a: List[Double], b: List[Double], /* ..., */ z: List[Double]): Something = 
      SomeObject.takesDoublesOrLists(a, b, z)
  }
}

// this context bound isn't really necessary, but it prevents you from creating V[String] you can't use
class V[A: DoubleOrList](
  val a: A,
  val b: A,
  // ...
  val z: A
)

class K[A](v: V[A])(implicit dOrL: DoubleOrList[A]) {
  def doIt = dOrL.doIt(v.a, v.b, /* ..., */ v.z)
}