Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.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_Initialization_Factory_Enforcement - Fatal编程技术网

在Scala中实施工厂的简明方法

在Scala中实施工厂的简明方法,scala,initialization,factory,enforcement,Scala,Initialization,Factory,Enforcement,让我们假设我们有一个特质T。实现以下目标的最佳方法是什么: 每个编写T实现的人都必须提供一种可能性,允许对T进行无参数初始化,即我们可能必须强制执行可配置工厂的实现 所有仅取决于实际初始化参数的逻辑/数据(特定实现的a或T)应集中处理/存储,但应在工厂和a中都可用 我认为实现这一点(大约)最简单/简洁的方法是为工厂添加一个特征,并将T链接到此工厂: trait T { val factory: TFactory } trait TFactory { def build(): T

让我们假设我们有一个特质
T
。实现以下目标的最佳方法是什么:

  • 每个编写
    T
    实现的人都必须提供一种可能性,允许对
    T
    进行无参数初始化,即我们可能必须强制执行可配置工厂的实现
  • 所有仅取决于实际初始化参数的逻辑/数据(特定实现的
    a
    T
    )应集中处理/存储,但应在工厂和
    a
    中都可用
我认为实现这一点(大约)最简单/简洁的方法是为工厂添加一个特征,并将
T
链接到此工厂:

trait T {
  val factory: TFactory
}
trait TFactory {
  def build(): T
  val description: String   // example for logic/data that only depend on the parameters
}

// example implementation:
class A(val factory: AFactory, paramA: Int, paramB: Int, paramC: Int) extends T

class AFactory(paramA: Int, paramB: Int, paramC: Int) extends TFactory {
  def build = new A(this, paramA, paramB, paramC)
  val description = f"$paramA $paramB $paramC"
}
显然,这并不能真正“强制”工厂的实现(只要有替代的实现可用),而且显然有可能生成链接到“错误”工厂的
a
的实例化。我也不喜欢这种方法重复初始化参数。我经常创建另一个类
AParams
,它再次包装所有参数(例如,为了方便添加新参数)。因此,我最终得到了三个类,这是这个简单问题的很多样板


我的问题是,是否有一种(可能完全)不同的方法,可以实现相同的主要目标,但更简洁?

我不太确定我是否完全理解您的需求,但您对这种行为有何看法

trait TFactory{
    def build():T
    val description:String
}

trait T extends TFactory

//can't declare A without build and not make it abstract
class A(paramA: Int, paramB: Int, paramC: Int) extends T {
    def build = new A(paramA, paramB, paramC)
    val description = f"$paramA $paramB $paramC"    
}

val a1 = new A(1, 4, 5)
val a2 = a1.build()

//We can give ourselves as a factory to something that expects TFactory
val factory:TFactory = a1
val a_new = factory.build()

//More likely we can just give our build method
def func(f: ()=>T) = {
    val new_t = f()
    new_t
}
val a_newer = func(a1.build)


println(a1 +": " + a1.description)
println(a2 +": " + a2.description)
println(a_new +": " + a_new.description)
println(a_newer +": " + a_newer.description)
输出:

Main$$anon$1$A@69267649: 1 4 5
Main$$anon$1$A@69b1fbf4: 1 4 5
Main$$anon$1$A@24148662: 1 4 5
Main$$anon$1$A@3f829e6f: 1 4 5

添加表示类型参数:

trait Factory[Prod] {
  def build(): Prod
}

trait Prod[Repr] {
  def factory: Factory[Repr]
}
或者,如果您希望“强制”该类型保持不变(除非您从中获得一些好处,否则我不会这样做):


绝对是个有趣的主意,谢谢!我看到的一个实际问题是,直觉上我将失去工厂是轻量级的概念,而
T
的实际实现可能相当重。在我的用例中,通常构建一个真正的
a
需要大量的初始化,从而导致
a
的实例占用大量内存。我可能经常会得到一个
A
的实例,我永远不会真正使用它作为
T
的实际意义,而只是作为一个具有不必要开销的工厂。但也许这就是简化的代价。似乎你需要在你的工厂中使用T的构造函数参数,所以我不明白你怎么能在没有T实例的情况下拥有这样一个工厂。除非,正如你所说,您将参数封装在一个类中,该类可以提供给工厂和T子类的构造函数。从设计角度讲,purefly我不确定您是否需要强制执行这样一个工厂,如果这不是构建T的唯一方法。可能您有一些方法需要工厂,它可以只是一个函数:
MakeTsAndDoUsefulThings(工厂:()=>T)
。然后在将来,如果我作为您的客户使用code make
SonOfT
并发现我需要使用该函数,我将为
SonOfT
实现一个工厂,可能在我的同伴对象中,并进行以下调用:
MakeTsAndDoUsefulThings(SonOfT.defaultFactory)
如果我永远不需要使用此方法,我再也不需要制造工厂了,这看起来还可以。
trait Prod[Repr <: Prod[Repr]] {
  def factory: Factory[Repr]
}
case class AConfig(a: Int, b: Int)

case class A(config: AConfig) extends Prod[A] {
  def factory = AFactory(config)
}

case class AFactory(config: AConfig) extends Factory[A] {
  def build() = A(config)
}

val f0 = AFactory(AConfig(1, 2))
val p0 = f0.build()
val f1 = p0.factory
val p1 = f1.build()
assert(p0 == p1)