Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Scala将功能混合到迭代过程的每个步骤中?_Scala_Design Patterns - Fatal编程技术网

如何使用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类表示,该类的构造函数被赋予前一步生

我正在Scala中进行一个优化过程,并寻求关于如何构造我的问题的建议。这个过程一步一个脚印,所以我用
步骤
类天真地模拟了这个问题:

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"