2010-10-22 62 views
3

例如(来自真实生活视图也许有点笨拙,但只是为了说明):我可以定义一个没有公共构造函数的类,并将这个类对象的工厂方法放在Scala中的另一个类中吗?

“用户”是情况下,包含的用户名和id类。 Id不能手动设置,而没有设置id的User类实例没有意义。

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

除了UserBase对象之外,没有人可以知道(可以,但真的不应该依赖此知识)用户的ID,因此手动构建User实例是没有意义的(并且可能会导致将来出现错误有人不小心硬编码并忘记)。此外,有一个孤儿用户实例没有跟踪UserBase也是不受欢迎的。

因此,任务是调用UserBase.getUser获取User实例的唯一方法。

这可以在Scala中实现吗?

+0

这个问题现在已经老了,你应该接受其中的一个答案。或者编辑它以提供更多信息,如果您没有得到您希望的答案。 – 2010-11-06 11:39:44

回答

2

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

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 = [email protected] 

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 = [email protected] 
1

一个case类会自动获取几个特征,包括一个带有apply()方法的伴随对象来构造类的实例。这就是为什么你不需要案例类的“新”。如果你尝试使用apply()来做一个明确的伴侣,你会得到error: method apply is defined twice

如果你想制作你自己的工厂方法,那么你不应该使用大小写类。你仍然可以拥有所有相同的功能(toString,apply,unapply等),但是你必须手动实现它们并且遵照你自己的规范。

+0

谢谢,知道一个有用的信息。但是这并没有回答这个问题,即在既定的(不同的)课程中,既不能构建也不能“适用”任何地方。在C++中,我可能会使用“朋友”定义(就我所知,我的C++经验在很多年以前)使私人成员可用于另一个类,但我不知道如何在Scala中实现这一点。 – Ivan 2010-10-22 19:57:36

+0

在scala中,您可以将'private'的层次结构设置为'private [what]',其中'what'可以是封装层或对象层次结构或'this'的封装层。有人回答下面的例子。 – 2010-10-22 20:33:48

1

其实你不弄清楚什么是“基地”在这种背景下,但鉴于你的描述,它听起来就像它真的没有什么比一个工厂用户更多。

通常的地方放一个工厂一类是在同伴的对象(这是case类是如何做到这一点,但该技术并不局限于只是 case类)

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") 

中当然,如果User对象是不可变的(强烈推荐),那么很少有理由隐藏id成员。你可能也想要一个(受限制的)方法来构造带有指定ID的User,主要是出于单元测试的原因。

与这样的同伴一起工作,您也不太可能需要独特的UserBase工厂。让您的工厂命名与其生成的实例相同将导致代码更简洁。

+0

当你将上述内容保存到一个文件中,并尝试从REPL中加载':load file'时,你可能会遇到这个问题:http://forums.pragprog.com/forums/87/topics/4153 – opyate 2011-06-12 01:51:48

相关问题