类的真正命名空间

时间:2013-04-21 12:51:34

标签: tcl

在构造函数,析构函数或方法中,我可以找出创建类的命名空间,因此我可以在其他类中调用card而不是将其编码为blackjack::card吗? / p>

namespace eval blackjack {

  oo::class create card {
    ...
  }

  oo::class create deck {
    constructor {} {
      my variable cards
      set cards {}
      for {set suit 0} {$suit < 4} {incr suit} {
        for {set value 0} {$value < 13} {incr value} {
          lappend cards [blackjack::card new $suit $value]
        }
      }
    }
    ...
  }

}

1 个答案:

答案 0 :(得分:3)

选项0:完全限定名称

你已经知道了这一点,而且我实际几乎总是这样做,因为它直接而简单。 (它是“选项0”,因为它没有提出问题。)

选项1:uplevel

你可以这样做:

lappend cards [uplevel 1 [list card new $suit $value]]

但这取决于从正确的命名空间调用deck new

选项2:类名手术

如果我们假设这两个类在同一名称空间中:

constructor {} {
    set cardClass [namespace qualifiers [self class]]::card
    # ...
        lappend cards [$cardClass new $suit $value]
    # ...
}

选项3:扩展对象的namespace path

如果你添加到对象的路径(NB:必须在构造函数中基于每个对象完成),那么你可以简单地引用另一个类:

constructor {} {
    namespace path [list {*}[namespace path] ::blackjack]
    # ...
        lappend cards [card new $suit $value]
    # ...
}

这里要注意的主要事项是TclOO设置了一个非平凡的默认namespace path(您认为nextself来自哪里?)

选项4:创建命令链接

您还有另一种选择,那就是使用namespace exportnamespace import来创建命令链接。

首先,从::blackjack命名空间中导出相关的类:

namespace eval ::blackjack {
    namespace export card;   # You probably want to export “deck” as well

    # ...
}

然后,在构造函数中执行导入:

constructor {} {
    namespace import ::blackjack::card
    # ...
        lappend cards [card new $suit $value]
    # ...
}

选项5:在deck实例

中创建一个特殊的子类

这个很棘手!

constructor {} {
    oo::class create card {superclass ::blackjack::card}
    # ...
        lappend cards [card new $suit $value]
    # ...
}

这也意味着当牌组消失时,卡片将被自动删除;你不需要在析构函数中销毁它们(因为它们的实际类将被自动删除,并且会杀死实例)。这可能是也可能不是你需要的。 (它确实为UML组合关系建模提供了一种好方法; TDBC在内部使用了一个变体来将语句与连接和结果集与语句相关联。)