class里定义object有何特殊含义?

fineqtbull 2009-10-10
Lift里Mapper的属性都是用object来定义,好像用object定义的属性是只读的,有点像val定义,但不知区别为何?如有知道的,还请指点一下。
import _root_.net.liftweb.mapper._
import _root_.java.math.MathContext
class Expense extends LongKeyedMapper[Expense]
with IdPK
{
  def getSingleton = Expense
  object dateOf extends MappedDateTime(this)
  object description extends MappedString(this,100)
  object amount extends MappedDecimal(this,
    MathContext.DECIMAL64, 2)
  object account extends MappedLongForeignKey(this, Account)
}
alanwu 2009-10-10
可以把object看成是特殊的class,可以认为他是class的单例。
object不是变量因此不能再赋值,但他里面的字段可以赋值。

lift的所有字段都用object表示,更突出lift里所有东西都是有实际业务意义的对象。


比如object dateOf extends MappedDateTime(this) 
如果在java中定义model可能就定义为: private Date dateOf; 那么他就是一个日期型字段,和bussiness model没太大关系。在Lift中,默认给这些字段类型定义了很多与业务相关的方法,比如asHtml,toForm,validate等,你也可以override这些默认方法。

这里的object可以当作是java的内类,
访问Scala的内类和访问方法一样用点。
object可以当作是实例化好的,因此不需要实例化,直接用就行了。
例如
Expense expense = Expense.create
expense.dateOf(current)

这里是调用了Expense的内类dateOf,再调用了dateOf的apply方法,
等同于
Expense expense = Expense.create
expense.dateOf.apply(current)
fineqtbull 2009-10-10
alanwu 写道

...
可以把object看成是特殊的class,可以认为他是class的单例。
...

这里所说的单例,是否是指class范围的单例呢?那就有点像java中的static属性了。但是object的定义中传入了this,那应该更像是和class的实例相对应吧。
alanwu 2009-10-10
fineqtbull 写道

这里所说的单例,是否是指class范围的单例呢?那就有点像java中的static属性了。但是object定义中的传入了this,那应该更像是和class的实例相对应吧。


对的,scala的object和java的static类似,但他确实又是class的变形,可以在里面定义字段,方法,甚至再定义内部类。
fineqtbull 2009-10-10
alanwu 写道
fineqtbull 写道

这里所说的单例,是否是指class范围的单例呢?那就有点像java中的static属性了。但是object定义中的传入了this,那应该更像是和class的实例相对应吧。


对的,scala的object和java的static类似,但他确实又是class的变形,可以在里面定义字段,方法,甚至再定义内部类。


那是否可以理解为object即定义了类似java中的static类(不包含this引用),又在class的实例构造过程中创建了实例中的只读属性(但可以传入this引用)。
alanwu 2009-10-10
我的理解是object就是特殊的class
scala没有static,这个可以当做static用
fineqtbull 2009-10-10
alanwu 写道
我的理解是object就是特殊的class
scala没有static,这个可以当做static用

我想说的是,Scala中class内定义的object定义了相当于Java的类中内嵌static类,而这里的object实例本身并不相当于java中的static属性,而是相当于val属性。据我理解,java中的内嵌staic类与一般内嵌类的差别是static类访问不到外部包含类的实例的this指针;static属性则是另一个概念,它是java类中的是全局范围的属性,可以认为相当于Scala中包范围的object(单例)。
下面是一个模拟Lift中Mapper的例子:

trait Mapper {
	var key : String = "key value"
}

class MappedString(val mapper:Mapper) {
  
	override def toString() : String = {
		super.toString() + ":" + mapper.key
	}
}

class Table1(keyStr : String) extends Mapper {
	key = keyStr
 
	object field1 extends MappedString(this)
 
 	override def toString() : String = {
 	  "field1:"+field1
 	}
 
}

object Main extends Application {
	val t1 = new Table1("key1")
 	val t2 = new Table1("key2")
	println(t1)
	println(t2)
	println(t1.field1)
//	var m = new Mapper {};
//	t1.field1 = new MappedString(m) //由于是object,不可以赋值
}


下为执行结果:
field1:Table1$field1$@22c95b:key1
field1:Table1$field1$@8814e9:key2
Table1$field1$@22c95b:key1


虽然field1是以object来定义的,但是不同的Table1实例有不同的field1属性,所以class中内嵌的object因该不可以称为单例,从效果来看更像val属性。
alanwu 2009-10-10
fineqtbull 写道

虽然field1是以object来定义的,但是不同的Table1实例有不同的field1属性,所以class中内嵌的object因该不可以称为单例,从效果来看更像val属性。


可以这么理解,所以scala object和java的static有本质区别。
他可以活在类实例上,同一个类不同实例上的object内容不一样,
而java的static是全局的,只能一样。

scala object如果独立存在,那他也能当全局的用。
night_stalker 2009-10-10
引用
The basic reason for this is that the MetaMapper needs access to
fields for its validation and form functionality; it is more difficult to cleanly define these properties
in the MetaMapper if it had to access member vars on each instance since a MetaMapper instance
is itself an object.


这种写法的不爽之处在于字段多了,就是满屏幕的 object ... extends ...
mapper 和 record 都不太好玩 …… 他们最好向 linq to sql 学习一下 ……

为了敲得快,我写了几个 snippet (vim 的 snipMate),稍微修改可以弄成 netbeans 的 code template:

snippet mapper
	/** ${1:comment}
	 */
	class ${2:klass} extends LongKeyedMapper[$2] with IdPK {
	  def getSingleton = $2
	  ${3}
	}

	/** $2 singleton (metamapper)
	 */
	object $2 extends $2
	  with LongKeyedMetaMapper[$2] {
	}
snippet fk
	MappedLongForeignKey(this, ${1})
snippet oe
	object ${1} extends ${2}
snippet m2m
	object ${1:other}s extends HasManyThrough(
	  this, ${2:Other}, ${3:JoinModel}, $3.$1, $3.${4})
alanwu 2009-10-10
Linq应该是纯粹的数据读写,而lift的mapper和record都带有业务功能,所以用途不一样。

像你说的那样,lift的这种方式不纯粹,混合了数据读写(ORM),业务功能,甚至页面展示,这样一个model做下来就比较庞大。好处也是比较明显,就是以业务model为中心,什么都集中在一起,开发起来比较快。
Global site tag (gtag.js) - Google Analytics