2015-01-10 81 views
3

我正在将一个C++程序移植到Scala中。在该项目中,组织层次结构中有数百个用户定义的类。根据Scala规则,如果我密封顶级抽象类之一,那么我必须将该类的所有子类型的定义与密封类/特征放在同一个文件中。对于我的类层次结构中的一个,它意味着将大约30个类的定义放在该文件中。密封有许多子类型的类

在我的C++程序中,这30个类位于它们自己的头文件和实现文件中,使它们更易于维护和读取。我担心,如果我将这30个类/对象的定义放在我的Scala应用程序的一个文件中,将会使它们难以维护和阅读。

密封类的原因是,我可以在这些类型的模式匹配时进行穷举搜索。值得赞赏的是,在组织Scala类层次结构方面,我指出正确的方向。

+0

如果班上有很多小类(在你的情况30),你可能不应该把它封闭起来。您不希望每次想要再次进行子类化时都必须更改它。 –

回答

2

假设你的类是其中有许多方法(这可能使你的文件增长)的情况下类,你可以使用类型类从实现尝试单独定义(但有时会afffect编译器的性能),如:

Model.scala

sealed trait A 
case class A1(a: Int) extends A 
case class A2(a: Int) extends A 
case class A3(a: Int, b: Int) extends A 
... 
case class A1(a: Int) extends A 

ImplA1.scala

package org.impl 
implicit class ImplA1(a: A1) { 
    def method1() = a.a + a.a 
} 

ImplA2.scala

package org.impl 
implicit class ImplA2(a: A2) { 
    def method1() = a.a * 2 
} 

用法:

import org.impl._ 
val a1 = new A1 
a1.method1() 
3

这是一个有点痛在单独的类来做到这一点,但它可能是比有一个巨大的文件,一切都那么痛苦。首先,您需要确保将所有文件一起编译。然后,在你的文件,你要确保一切是密封的,你做到以下几点:

trait GenericA { def foo: Int } 
sealed trait A extends GenericA 
case class B() extends A with ImplB {} 
case class C() extends A with ImplC {} 
... 

诀窍是,一切都在超类(它可以是一个抽象类,而不是一个特征,如果你愿意的话)去到GenericA。但你永远不会在你的代码中使用使用GenericA,你只需使用A。现在,你可以写一堆的每个执行单独的文件,像这样定义的:

// File #1 
trait ImplB extends GenericA { def foo = 7 } 

// File #2 
trait ImplC extends GenericA { def foo = 4 } 

... 

现在,你有你的实现分离出来(这只能在Generica产品来表示,至少那些部分)。

如果您还需要可用的案例类参数,该怎么办?没问题 - 只包括那些作为特质的一部分。

// Main file 
case class D(i: Int) extends A with ImplD {} 

// Separate file 
trait ImplD { 
    def i: Int 
    def foo = i*3 
} 

这一点额外的工作,因为你不得不重复在两个点的情况下类参数,但在你的情况下,它可能是值得的。