我想知道为什么smalltalk没有使用java风格的内部类。这种机制有效地允许您在需要时随时随地定义新类的新实例。当你需要一个符合某些特定协议的对象但你不想为它创建一个普通的类时,它会很方便,因为它的临时和本地特性非常具体。 据我所知,它可以很容易地完成,因为子类化的语法是标准的消息发送。你可以将自己传递给它,因此它具有“外部”对象的概念。唯一的问题是匿名 - 该类不应出现在对象浏览器中,并且在没有实例退出时必须进行垃圾回收。 问题是:有没有人想到这个?
答案 0 :(得分:3)
如果您正在考虑使用内部类进行测试,那么您还可以查看类ClassFactoryForTestCase
答案 1 :(得分:3)
在smalltalk中创建一个匿名类是件小事。 更重要的是,任何具有3个实例变量的对象都可以正确设置为:它的超类,方法字典和实例格式可以作为一个类(有实例)。 所以,我不知道这里有什么问题。
如果你谈论工具支持,比如浏览或导航这些类中包含的代码,这是不同的故事。因为默认情况下系统中的所有类都是公共的,系统字典是它们的平面命名空间(是的,某些实现具有命名空间)。这个简单的模型在大多数时候都很有效。
答案 2 :(得分:2)
我很确定可以通过围绕Class和Metaclass协议进行一些黑客攻击来完成。这个问题经常出现在拥有更多Java经验的人身上,Smalltalk对他们很有趣。由于内部类尚未实现,我认为它是大多数Smalltalk用户发现它们无法使用的标志。这可能是因为Smalltalk有块,它以更简单的方式解决导致将内部类引入Java的许多(如果不是全部)问题。
答案 3 :(得分:2)
这里有两个答案:
1 - 是的,创建自动收集垃圾的匿名类并不难。在Squeak中,它们被称为“uniclasses”,因为典型的用例是将方法添加到单个对象。使用它的系统例如是Etoys和Tweak(尽管在Etoys中,由于历史原因,类实际上被放入SystemDict)。这是我最近使用的一些吱吱声代码:
newClass := ClassBuilder new
newSubclassOf: baseClass
type: baseClass typeOfClass
instanceVariables: instVars
from: nil.
baseClass removeSubclass: newClass.
^newClass
通常,您需要添加便捷方法来执行此操作。然后,您可以添加方法,并创建一个实例,当所有实例都消失后,该类也将被gc'ed。
请注意,在Java中,类对象不是gc'ed - 内部类的编译方式与常规类完全相同,它只能被编译器隐藏。相比之下,在Smalltalk中,这一切都发生在运行时,甚至是为这个类编译新方法,这使得它相对低效。有一种更好的方法来创建匿名预编译行为,这使我们回答2:
2 - 即使它并不难,但它很少用于Smalltalk。原因是Smalltalk有一个更方便的机制。 Java中的内部类通常用于构建实现特定接口的方法。只需要使编译器对类型安全感到满意,就需要内部类声明。 在Smalltalk中,您只需使用块闭包。这使您可以动态创建可以传递的行为。系统库的结构是利用块闭包的方式。
我个人从未觉得内部课程是Smalltalk所需要的。
答案 4 :(得分:1)
(a)您可以发送消息以从另一个类的方法内部创建一个新类
(b)我怀疑将结果类隐藏在内省系统中有什么好处
(c)在Java中使用内部类的原因是因为没有第一类函数。如果你需要在Smalltalk中传递一段代码,你只需传递一个块。你不需要用其他类型的对象来包装它。
答案 5 :(得分:0)
问题(至少在吱吱声中)来自于缺乏清晰的关注点分离。创建自己的子类并将其放在私有SystemDictionary
:
myEnv := SystemDictionary new.
myClass := ClassBuilder new
name: 'MyClass'
inEnvironment: myEnv
subclassOf: Object
type: #normal
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'MyCategory'
unsafe: false.
但即使你把这个课程放在你自己的SystemDictionary
中,'MyCategory'类别也会添加到系统导航中(通过打开Browser
可以验证),而且 - 更糟糕的是 - 课程组织者不是' t创建,所以当你导航到MyClass
时,你会得到一个零指针。
从理论上讲,这当然不是不可能的。现在,工具面向一个全局可见的类定义池。