Class 我可以定义一个没有公共构造函数的类,并将该类对象的工厂方法放在Scala中的另一个类中吗?

Class 我可以定义一个没有公共构造函数的类,并将该类对象的工厂方法放在Scala中的另一个类中吗?,class,scala,constructor,factory,Class,Scala,Constructor,Factory,例如(从现实生活的角度来看可能有点笨拙,但只是为了举例说明): “User”是一个包含用户名和id的case类。id永远不能手动设置,没有id设置的用户类实例没有意义 UserBase类维护users库,并有一个“getUser(name:String):User”方法返回一致的用户实例 除了UserBase对象之外,没有人可以知道(当然,有人可以知道,但确实不应该依赖于这些知识)用户id,因此手动构造用户实例没有意义(如果有人意外地硬编码并忘记了这一点,将来可能会导致错误)。此外,让一个孤立的

例如(从现实生活的角度来看可能有点笨拙,但只是为了举例说明):

“User”是一个包含用户名和id的case类。id永远不能手动设置,没有id设置的用户类实例没有意义

UserBase类维护users库,并有一个“getUser(name:String):User”方法返回一致的用户实例

除了UserBase对象之外,没有人可以知道(当然,有人可以知道,但确实不应该依赖于这些知识)用户id,因此手动构造用户实例没有意义(如果有人意外地硬编码并忘记了这一点,将来可能会导致错误)。此外,让一个孤立的用户实例不被用户库跟踪也是不可取的

因此,任务是使调用UserBase.getUser成为获取用户实例的唯一方法


这可以在Scala中实现吗?

一个case类会自动获得几个特性,包括一个带有apply()方法的伴生对象,用于构造该类的实例。这就是为什么您不需要“新”的案例类。如果您试图与apply()明确搭配,您将得到
错误:apply方法定义了两次


如果您想创建自己的工厂方法,那么不应该使用case类。您仍然可以拥有所有相同的功能(toString、apply、unapply等),但您必须手动并按照自己的规范实现这些功能。

您必须将这些类放在同一个包中,或者使它们成为同一个类或对象的一部分。然后:

object O {
  class C private[O] (val x: Int) { }
  object D { def apply(i:Int) = new C(i) }
  def getC(i:Int) = new C(i)
}

scala> O.D(5)
res0: O.C = O$C@5fa6fb3e

scala> new O.C(5)
<console>:10: error: constructor C cannot be accessed in object $iw
       new O.C(5)

scala> O.getC(5)
res1: O.C = O$C@127208e4
对象O{
C类私有[O](val x:Int){}
对象D{def apply(i:Int)=新的C(i)}
def getC(i:Int)=新的C(i)
}
scala>外径(5)
res0:O.C=O$C@5fa6fb3e
scala>新O.C(5)
:10:错误:无法在对象$iw中访问构造函数C
新O.C(5)
scala>O.getC(5)
res1:O.C=O$C@127208e4

在这个上下文中,您实际上并没有阐明什么是“基础”,但根据您的描述,它听起来就像是用户的工厂

为类放置工厂的通常位置是在伴生对象中(case类就是这样做的,但该技术并不局限于case类)

当然,如果用户对象是不可变的(强烈建议),那么几乎没有理由隐藏id成员。您可能还需要一个(受限)方法来构造一个具有指定ID的
用户
,这主要是出于单元测试的原因


与这样的伙伴一起工作,您也不太可能仍然需要一个独特的
UserBase
工厂。将您的工厂命名为与其生产的实例相同的名称将导致代码更清晰。

谢谢,这是一个有用的信息。但这并不能回答这个问题,即除了在一个特定的(不同的)类中,构造函数和“应用”在任何地方都不可用。在C++中,我可能会使用“朋友”定义(据我所记得的,我的C++体验很多年前),让一个私有成员可用于另一个类,但是我不知道如何在Scala中实现这个。在Scala中,可以为私下<代码>的层次结构级别设置为<代码>私有[什么]。
where
what
可以是包或对象层次结构的封闭级别,也可以是
this
。下面有人举了一个例子来回答。这个问题现在已经过时了,你可能应该接受其中一个答案。或者,如果您没有得到您希望的答案,请编辑它以提供更多信息。请注意,当将上述内容保存到文件中,并尝试从REPL加载文件时,您可能会遇到以下问题:
class User private(val id: Int, val name: String) {
  ...
}

object User {
  private def nextId() : Int = ...
  def apply(name: String) = new User(nextId(), name)
}

//now create one:
val u = User("Ivan")