如何使用Scala将功能混合到迭代过程的每个步骤中?
我正在Scala中进行一个优化过程,并寻求关于如何构造我的问题的建议。这个过程一步一个脚印,所以我用如何使用Scala将功能混合到迭代过程的每个步骤中?,scala,design-patterns,Scala,Design Patterns,我正在Scala中进行一个优化过程,并寻求关于如何构造我的问题的建议。这个过程一步一个脚印,所以我用步骤类天真地模拟了这个问题: class Step(val state:State) { def doSomething = ... def doSomethingElse = ... def next:Step = ... // produces the next step in the procedure } 过程中的每一步都由不可变的step类表示,该类的构造函数被赋予前一步生
步骤
类天真地模拟了这个问题:
class Step(val state:State) {
def doSomething = ...
def doSomethingElse = ...
def next:Step = ... // produces the next step in the procedure
}
过程中的每一步都由不可变的step
类表示,该类的构造函数被赋予前一步生成的状态,其next
方法生成后续的step
实例。基本思想是使用迭代器[Step]
将其包装起来,这样就可以采取步骤,直到优化收敛为止。虽然有点简单化,但这对于一般情况来说效果很好
然而,现在,我需要为算法添加各种扩展,我需要根据优化的问题任意混合这些扩展。通常情况下,这将通过可堆叠的特征模式来实现,但这种方法会给这个问题带来问题。下面是两个可能的扩展的示例:
trait FeatureA extends Step {
// Extension-specific state passed from step to step
val aState:FeatureAState = ...
// Wrap base methods to extend functionality
abstract override def doSomething = { ...; super.doSomething(); ... }
}
// Just like Feature A
trait FeatureB extends Step {
val bState:FeatureBState = ...
abstract override def doSomething = { ...; super.doSomething(); ... }
}
有时优化需要将featureurea
混合在一起,有时需要将FeatureB
混合在一起,有时两者都需要
主要问题是基类的next
方法不知道混合了哪些扩展,因此后续生成的步骤不会将任何扩展合并到初始步骤中
此外,每个扩展都需要一步一步地传递自己的状态。在本例中,FeatureAState
/FeatureBState
实例包含在各自的trait中,但如果不重写next
方法,FeatureA
和FeatureB
无法传递其唯一状态。无法在每个trait中重写next
,因为可能混合了这些扩展的组合,并且每个扩展只知道自己
看来我已经把自己画进了一个角落,我希望有人能对如何使用Scala来实现这一点有所了解。哪种设计模式最适合这种类型的问题?您可能有兴趣探索这种模式。此模式允许您定义返回trait或基类中当前子类型的方法。以下是您的示例的简化版本:
trait Step[T <: Step[T]] { self: T =>
val name: String
def next: T
}
case class BasicStep(name: String) extends Step[BasicStep] {
def next = this.copy(name = name + "I")
}
case class AdvancedStep(baseName: String, iteration: Int) extends Step[AdvancedStep] {
val name = s"$baseName($iteration)"
def advancedFunction = println("foobar")
def next = this.copy(iteration = iteration + 1)
}
如果您想像这样混入多个类型,很遗憾,您不能使用泛型(您将收到“inherits different type instances of trait”错误)。但是,您可以使用抽象类型成员来表示F绑定多态性:
trait Step { self =>
type Self <: Step { type Self = self.Self }
val name: String
def next: Self
}
trait Foo extends Step {
val fooMarker = "foo"
}
trait Bar extends Step {
val barMarker = "bar"
}
case class FooBar(name: String) extends Foo with Bar {
override type Self = FooBar
def next = this.copy(name + "I")
}
请注意,该名称来自
Foo
,因为它首先被混合在一起。感谢您的回复。这差不多就是我现在拥有的。问题是我希望能够同时混合BasicStep
和AdvancedStep
。每个trait都在基类中包装了任何相关的方法/val,以便添加功能,这里没有问题。问题的关键似乎是,每一步都会产生下一步,而mixin无法将自己(及其状态)合并到新构造的步骤中。似乎我必须采取一种完全不同的方法。我一直在思考的另一个选择是将步骤
更改为特征,而将下一步
保留为未实现(如您所建议)。现在我们的整个层次结构只包含特征。然后,对于每个特性组合,创建一个具体的类,将所有内容混合在一起,并在那里实现next
。我认为这是可行的,但是为每个特性组合创建一个具体类的想法似乎很尴尬。嗨,Ben,我尝试了更新的方法,虽然它确实有效,但我不喜欢为每个混合的组合创建一个具体类。这只是创建了太多的样板文件,而且每增加一个特性都会变得更糟。我最终重构了我的代码以完全避免这个问题,虽然不理想,但我将此标记为解决方案,因为它可能是其他人可以接受的途径。谢谢你的帮助!很高兴我能提供任何帮助。如果你想在这里分享你的答案,我很想看看(如果它仍然是原始问题的相关答案)通过模块化每个步骤的基本计算,并允许将不同的实现插入step
类,而不是直接覆盖它,我能够解决这个问题。这样Step.next
只需将这些模块传递到下一个Step
实例。到目前为止,我很高兴这是多么干净和简单的工作,希望它将被证明是足够普遍的未来扩展了。
trait Step { self =>
type Self <: Step { type Self = self.Self }
val name: String
def next: Self
}
trait Foo extends Step {
val fooMarker = "foo"
}
trait Bar extends Step {
val barMarker = "bar"
}
case class FooBar(name: String) extends Foo with Bar {
override type Self = FooBar
def next = this.copy(name + "I")
}
val fooBar = FooBar("foobar").next.next
fooBar.barMarker //"bar"
fooBar.fooMarker //"foo"
fooBar.name //"fooNameII"