Я пытаюсь реализовать иерархическую структуру классов/подклассов объектов, например:
|-- Class1 # mainClass
| |-- SubClassA # subClass
| `-- SubClassB # subClass
`-- Class2 # mainClass
|-- SubClassA # subClass
`-- SubClassB # subClass
Главное здесь — иметь возможность объявлять разные подклассы, имеющие одно и то же имя в каждом основном классе (и иметь независимые переменные).
(Примечание: здесь я говорю об иерархии классов объектов, созданных во время выполнения, а не о наследии разных классов.)
Совершенно не знакомый с некоторыми расширенными аспектами, характерными для Tcl (пространство имен, область действия...), я попробовал следующий код:
package require Itcl
itcl::class subClass {
variable InternalVariable
constructor {} {
puts "($this) Current namespace : [namespace current]"
puts "($this) InternalVariable scope : [itcl::scope InternalVariable]"
}
}
itcl::class mainClass {
variable SubClassesList
constructor {} {
set SubClassesList {}
puts "($this) current namespace : [namespace current]"
puts "($this) SubClassesList scope : [itcl::scope SubClassesList]"
}
method newSubClass {argName} {
lappend SubClassesList [subClass $argName]
puts "($this) SubClassesList : {$SubClassesList}"
}
}
# Create the two main classes
mainClass Class1
mainClass Class2
# Add some subclasses to Class1 and Class2
Class1 newSubClass SubClassA
Class1 newSubClass SubClassB
Class2 newSubClass SubClassC
Class2 newSubClass SubClassB
который выдает ошибку при создании второго вхождения SubClassB
:
(::Class1) current namespace : ::mainClass
(::Class1) SubClassesList scope : @itcl ::Class1 ::mainClass::SubClassesList
(::Class2) current namespace : ::mainClass
(::Class2) SubClassesList scope : @itcl ::Class2 ::mainClass::SubClassesList
(::mainClass::SubClassA) Current namespace : ::subClass
(::mainClass::SubClassA) InternalVariable scope : @itcl ::mainClass::SubClassA ::subClass::InternalVariable
(::Class1) SubClassesList : {SubClassA}
(::mainClass::SubClassB) Current namespace : ::subClass
(::mainClass::SubClassB) InternalVariable scope : @itcl ::mainClass::SubClassB ::subClass::InternalVariable
(::Class1) SubClassesList : {SubClassA SubClassB}
(::mainClass::SubClassC) Current namespace : ::subClass
(::mainClass::SubClassC) InternalVariable scope : @itcl ::mainClass::SubClassC ::subClass::InternalVariable
(::Class2) SubClassesList : {SubClassC}
command "SubClassB" already exists in namespace "::mainClass"
Я, вероятно, упускаю момент о пространствах имен классов, потому что я не понимаю, как переменная SubClassesList
может иметь две разные области, но «одно и то же» пространство имен/имя (из вывода отладки).
Я попытался создать новое пространство имен в методе newSubClass
, но это не решило проблему и/или добавило некоторые неразрешимые ошибки пространств имен переменных...
method newSubClass {argName} {
set SubClassName "[namespace current]::[namespace tail $this]"
puts "($this) SubClassName : $SubClassName"
namespace eval $SubClassName "lappend SubClassesList [subClass $argName]"
puts "($this) SubClassesList : {$SubClassesList}"
}
Любая идея выполнить такую вещь?
P-S: я использовал [incr Tcl] для реализации классов в своем проекте из соображений совместимости с существующей средой, но если кто-то считает, что другая реализация OO будет лучше/проще, дайте мне знать...
РЕДАКТИРОВАТЬ :
Нашел решение, используя namespace eval
+ namespace inscope
для создания subClass
объектов в новом пространстве имен, соответствующем имени mainClass
объектов:
itcl::class mainClass {
variable SubClassesList
constructor {} {
set SubClassesList {}
puts "($this) current namespace : [namespace current]"
puts "($this) SubClassesList scope : [itcl::scope SubClassesList]"
# Create a new namespace corresponding to class name
namespace eval $this {}
}
method newSubClass {argName} {
# Create the subClass object in the $this namespace
lappend SubClassesList [namespace inscope $this subClass $argName]
puts "($this) SubClassesList : {$SubClassesList}"
}
}