如何通过对代码库进行最少的更改来丰富案例 class?
How do I enrich a case class with minimal changes to the codebase?
使用 scala 2.11.12.
分散在我的代码库中我有一个这样的案例class:
case class Landscape(
north: Sight,
east: Sight,
south: Sight,
west: Sight
) {
def toList: List[Sight] = List(north, east, south, west)
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
(带有自定义案例 class Sight
)和相应的伴生对象:
object Landscape {
def fromSeq(s: Seq[Sight]): Landscape = {
require(s.length == 4)
Landscape(
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
def pickByBeautifulSouth(scape1: Landscape, scape2: Landscape): Landscape = {
if (scape1.south.beauty > scape2.south.beauty) scape1 else scape2
}
}
事实证明,拥有相似的类型会很有用,所以我创建了一个通用案例 class:
case class Compass[A](
north: A,
east: A,
south: A,
west: A
) {
def toList: List[A] = List(north, east, south, west)
}
与相应的伴随对象:
object Compass {
def fromSeq[A](s: Seq[A]): Compass[A] = {
require(s.length == 4)
Compass[A](
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
}
显然 isIdyllic
和 pickByBeautifulSouth
对任意类型 A
没有意义。
现在我想使 Landscape
成为一个丰富的 Compass
,这样我就不必再在 Landscape
中定义 toList
和 fromSeq
。
我知道我做不到
case class Landscape(
north: Sight,
east: Sight,
south: Sight,
west: Sight
) extends Compass[Sight] {
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
因为个案继承是不可能的。我也不能使 Compass[A] 成为这样的特征:
trait Compass[A]{
def north: A
def east: A
def south: A
def west: A
def toList: List[A] = List(north, east, south, west)
}
因为那样我会破坏 fromSeq
,它利用了 Compass
的字段及其应用方法。
我也想过使用隐式 class
implicit class LandscapeOps(ls: Compass[Sight]) {
def isIdyllic: Boolean = ls.north.isPastoral && ls.east.isPastoral && ls.south.isPastoral && ls.west.isPastoral
}
和我的代码库中的类型别名
type Landscape = Compass[Sight]
但是,这样一来我又会因为失去 Landscape
的应用方法而破坏我的代码。而且我也不知道如何添加 pickByBeautifulSouth
.
长话短说:我正在寻找方法
- 使
Landscape
使用 Compass
,这样我就不必复制 toList
和 fromSeq
- 通过对代码库进行最小的更改来实现这一点,即
Landscape(sight1, sight2, sight3, sight4)
和 Landscape.copy(west=someSight)
应该仍然有效,Landscape.pickByBeautifulSouth(scape1, scape2)
不确定我是否理解所有的限制,但是..
为什么不是特征 Compass[T]
和子类型 Landscape
trait Compass[A] {
val north: A
val east: A
val south: A
val west: A
def toList: List[A] = List(north, east, south, west)
}
case class Landscape(
north: Sight,
east: Sight,
south: Sight,
west: Sight
) extends Compass[Sight] {
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
那么整个 Landscape 对象仍然有效
object Landscape {
def fromSeq(s: Seq[Sight]): Landscape = {
require(s.length == 4)
Landscape(
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
def pickByBeautifulSouth(scape1: Landscape, scape2: Landscape): Landscape =
???
}
所以这是我最终得到的一个最小工作示例:
case class Sight() {
def isPastoral: Boolean = true
def beauty: Int = 5
}
case class Compass[A](
north: A,
east: A,
south: A,
west: A
) {
def toList: List[A] = List(north, east, south, west)
}
object Compass {
def fromSeq[A](s: Seq[A]): Compass[A] = {
require(s.length == 4)
Compass[A](
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
}
object LandscapeModule {
type Landscape = Compass[Sight]
val Landscape = Compass
implicit class LandscapeOps(ls: Landscape) {
import ls._
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
object LandscapeOps {
def pickByBeautifulSouth(scape1: Landscape, scape2: Landscape): Landscape = {
if (scape1.south.beauty > scape2.south.beauty) scape1 else scape2
}
}
}
object HowToUseIt {
import LandscapeModule.{Landscape, LandscapeOps}
val sight = Sight()
val sights: Seq[Sight] = Seq.fill(4)(sight)
val landscape: Landscape = Landscape(north = sight, east = sight, south = sight, west = sight)
val landscapeFromSeq = Landscape.fromSeq(sights)
LandscapeOps.pickByBeautifulSouth(landscape, landscapeFromSeq)
}
这样我只需更改我的代码库中的两件事:
- 导入:
import LandscapeModule.{Landscape, LandscapeOps}
而不是 import Landscape
- 除了
fromSeq
之外调用景观的自定义工厂方法:LandscapeOps.pickByBeautifulSouth
而不是 Landscape.pickByBeautifulSouth
使用 scala 2.11.12.
分散在我的代码库中我有一个这样的案例class:
case class Landscape(
north: Sight,
east: Sight,
south: Sight,
west: Sight
) {
def toList: List[Sight] = List(north, east, south, west)
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
(带有自定义案例 class Sight
)和相应的伴生对象:
object Landscape {
def fromSeq(s: Seq[Sight]): Landscape = {
require(s.length == 4)
Landscape(
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
def pickByBeautifulSouth(scape1: Landscape, scape2: Landscape): Landscape = {
if (scape1.south.beauty > scape2.south.beauty) scape1 else scape2
}
}
事实证明,拥有相似的类型会很有用,所以我创建了一个通用案例 class:
case class Compass[A](
north: A,
east: A,
south: A,
west: A
) {
def toList: List[A] = List(north, east, south, west)
}
与相应的伴随对象:
object Compass {
def fromSeq[A](s: Seq[A]): Compass[A] = {
require(s.length == 4)
Compass[A](
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
}
显然 isIdyllic
和 pickByBeautifulSouth
对任意类型 A
没有意义。
现在我想使 Landscape
成为一个丰富的 Compass
,这样我就不必再在 Landscape
中定义 toList
和 fromSeq
。
我知道我做不到
case class Landscape(
north: Sight,
east: Sight,
south: Sight,
west: Sight
) extends Compass[Sight] {
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
因为个案继承是不可能的。我也不能使 Compass[A] 成为这样的特征:
trait Compass[A]{
def north: A
def east: A
def south: A
def west: A
def toList: List[A] = List(north, east, south, west)
}
因为那样我会破坏 fromSeq
,它利用了 Compass
的字段及其应用方法。
我也想过使用隐式 class
implicit class LandscapeOps(ls: Compass[Sight]) {
def isIdyllic: Boolean = ls.north.isPastoral && ls.east.isPastoral && ls.south.isPastoral && ls.west.isPastoral
}
和我的代码库中的类型别名
type Landscape = Compass[Sight]
但是,这样一来我又会因为失去 Landscape
的应用方法而破坏我的代码。而且我也不知道如何添加 pickByBeautifulSouth
.
长话短说:我正在寻找方法
- 使
Landscape
使用Compass
,这样我就不必复制toList
和fromSeq
- 通过对代码库进行最小的更改来实现这一点,即
Landscape(sight1, sight2, sight3, sight4)
和Landscape.copy(west=someSight)
应该仍然有效,Landscape.pickByBeautifulSouth(scape1, scape2)
不确定我是否理解所有的限制,但是..
为什么不是特征 Compass[T]
和子类型 Landscape
trait Compass[A] {
val north: A
val east: A
val south: A
val west: A
def toList: List[A] = List(north, east, south, west)
}
case class Landscape(
north: Sight,
east: Sight,
south: Sight,
west: Sight
) extends Compass[Sight] {
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
那么整个 Landscape 对象仍然有效
object Landscape {
def fromSeq(s: Seq[Sight]): Landscape = {
require(s.length == 4)
Landscape(
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
def pickByBeautifulSouth(scape1: Landscape, scape2: Landscape): Landscape =
???
}
所以这是我最终得到的一个最小工作示例:
case class Sight() {
def isPastoral: Boolean = true
def beauty: Int = 5
}
case class Compass[A](
north: A,
east: A,
south: A,
west: A
) {
def toList: List[A] = List(north, east, south, west)
}
object Compass {
def fromSeq[A](s: Seq[A]): Compass[A] = {
require(s.length == 4)
Compass[A](
north = s(0),
east = s(1),
south = s(2),
west = s(3)
)
}
}
object LandscapeModule {
type Landscape = Compass[Sight]
val Landscape = Compass
implicit class LandscapeOps(ls: Landscape) {
import ls._
def isIdyllic: Boolean = north.isPastoral && east.isPastoral && south.isPastoral && west.isPastoral
}
object LandscapeOps {
def pickByBeautifulSouth(scape1: Landscape, scape2: Landscape): Landscape = {
if (scape1.south.beauty > scape2.south.beauty) scape1 else scape2
}
}
}
object HowToUseIt {
import LandscapeModule.{Landscape, LandscapeOps}
val sight = Sight()
val sights: Seq[Sight] = Seq.fill(4)(sight)
val landscape: Landscape = Landscape(north = sight, east = sight, south = sight, west = sight)
val landscapeFromSeq = Landscape.fromSeq(sights)
LandscapeOps.pickByBeautifulSouth(landscape, landscapeFromSeq)
}
这样我只需更改我的代码库中的两件事:
- 导入:
import LandscapeModule.{Landscape, LandscapeOps}
而不是import Landscape
- 除了
fromSeq
之外调用景观的自定义工厂方法:LandscapeOps.pickByBeautifulSouth
而不是Landscape.pickByBeautifulSouth