2014-10-03 79 views
1

我是Smalltalk(VisualAge环境)中的新成员,我尝试创建一个计算她的实例数的类。不幸的是,当我重写'新'方法时,某些东西不能工作。这是我的类代码:如何在Smalltalk中创建一个类的实例?

Object subclass: #TestClassB 
    instanceVariableNames: 'niceVariable ' 
    classVariableNames: 'InstanceCounter ' 
    poolDictionaries: ''! 

!TestClassB class publicMethods ! 

initWithNiceParameter: parameter 

    |testClassBInstance| 

    testClassBInstance:= self new. 
    ^(testClassBInstance niceVariable: parameter)! 

new 
    super new. 
    InstanceCounter isNil 
     ifTrue: [InstanceCounter := 0] 
     ifFalse: [InstanceCounter := InstanceCounter + 1]. 
    ^self 
    ! ! 

!TestClassB publicMethods ! 

niceVariable: anObject 
    "Save the value of niceVariable." 
    niceVariable := anObject. 
! ! 

我想用 'initWithNiceParameter' 消息新的对象:

TestClassB initWithNiceParameter: 'my super string' 

但我得到的是错误:

TestClassB does not understand niceVariable: 

这是因为'TestClassB'也是一个对象,似乎它没有'niceVariable'setter。

当'新'方法被忽略时,您是否有任何想法如何创建对象?

回答

3

您的方法new的执行返回self。值self还有TestClassB类,因为new是类方法,而self是类方法本身。

您应该返回得到通过发送super new创建的对象:

new 
    |instance| 
    instance := super new. 
    InstanceCounter isNil 
     ifTrue: [InstanceCounter := 0] 
     ifFalse: [InstanceCounter := InstanceCounter + 1]. 
    ^instance 

或更短:

new 
    InstanceCounter isNil 
     ifTrue: [InstanceCounter := 0] 
     ifFalse: [InstanceCounter := InstanceCounter + 1]. 
    ^super new 
+1

虽然我们正在改进,让我们初始化InstanceCounter在零端#初始化并完全删除分支;) – 2014-10-03 16:12:27

+0

将'TestClassB allInstances大小'不够? – 2014-10-03 17:17:47

+0

@SeanDeNigris你的意思是#initialize和删除分支?我创建了这个方法(它与#new一样是类方法),它重写了Object类中的#initialize,但它不会通过创建新对象来自动调用。 – user3452568 2014-10-06 10:20:17

0

略OT,但#ifTrue:ifFalse是不必要的复杂。 Smalltalk的方式来初始化类级别的变量是一类端#初始化*像这样:

TestClassB class>>#initialize 
    InstanceCounter := 0 

现在,当你加载TestClassB到系统中,InstanceCounter将被初始化,您可以从Johan's short version简化:

TestClassB class>>#new 
    InstanceCounter := InstanceCounter + 1. 
    ^super new 
  • 或懒洋洋地
+0

不应该是'TestClassB >>#new'类方法吗?像这样:'TestClassB class >>#new'? – user3452568 2014-10-07 07:41:41

+0

哈哈是的,你是对的。很好!我只是从上面复制粘贴... – 2014-10-07 11:17:25

0

我很困惑,因为我不知道,如果#initialize方法是自动调用。我使用VisualAge 7.5,我注意到,如果您使用GUI创建一个新类(右键单击“新建” - >“部分...”),然后保存它,#initialize不会自动调用!即使你在工作区中创建了一个类的实例。但是如果你导出你的类然后再加载它,#initialize被调用。更具体地说,类定义看起来像这样:

Object subclass: #InitTest 
    instanceVariableNames: '' 
    classVariableNames: '' 
    poolDictionaries: ''! 

!InitTest class publicMethods ! 

initialize 
Transcript show: 'initialize method'; cr.! 
new 
Transcript show: 'new method'; cr. 
^super new.! ! 

InitTest initialize! "<- it's created automatically" 
InitTest initializeAfterLoad! 

我认为这非常棘手。你知道如何(重新)在VisualAge工作区中加载类定义,以确保调用了#initialize(没有写入InitTest初始化)?

+0

在Pharo中,如果类已经加载,典型的方法是发送'''InitTest initialize'''。你为什么要避免这种情况?这只是为了方便开发...... – 2014-10-07 11:22:48

+0

我想我现在明白你的问题。当您加载类或显式调用类时,将调用类方#initialize。实例端#initialize应该从类端#new调用。在Pharo中,这是自动完成的,但不能用于其他方言。欲了解更多信息,请参阅http://stackoverflow.com/questions/5692844/difference-between-new-and-initialize-in-smalltalk – 2014-10-08 03:20:16

相关问题