玩杂耍多个对象实例

时间:2008-12-08 06:56:32

标签: oop abstract

这个问题是用伪PHP编写的,但我真的不介意我得到什么语言(除了Ruby :-P),因为这纯粹是假设的。事实上,PHP很可能是做这种逻辑的最糟糕的语言。不幸的是,我以前从未这样做过,所以我无法提供一个真实的例子。因此,假设的答案是完全可以接受的。

基本上,我有很多对象执行任务。对于此示例,假设每个对象都是从Internet下载文件的类。每个对象将下载不同的文件,并且下载并行运行。显然,有些对象可能会在其他对象之前完成下载。实际抓取数据可能会在线程中运行,但这与此问题无关。

所以我们可以这样定义对象:

class DownloaderObject() {
    var $url = '';
    var $downloading = false;

    function DownloaderObject($v){ // constructor
        $this->url = $v;
        start_downloading_in_the_background(url=$this->$url, callback=$this->finished);
        $this->downloading = true;
    }

    function finished() {
        save_the_data_somewhere();
        $this->downloading = false;
        $this->destroy(); // actually destroys the object
    }
}

好的,我们运行了很多这样的对象:

$download1 = new DownloaderObject('http://somesite.com/latest_windows.iso');
$download2 = new DownloaderObject('http://somesite.com/kitchen_sink.iso');
$download3 = new DownloaderObject('http://somesite.com/heroes_part_1.rar');

我们可以将它们存储在一个数组中:

$downloads = array($download1, $download2, $download3);

所以我们有一个充满下载的数组:

array(
  1 => $download1,
  2 => $download2,
  3 => $download3
)

我们可以像这样迭代它们:

print('Here are the downloads that are running:');
foreach ($downloads as $d) {
    print($d->url . "\n");
}

好的,现在假设下载2完成,对象被破坏。现在我们应该在数组中有两个对象:

array(
  1 => $download1,
  3 => $download3
)

但阵列中有一个洞!密钥#2未被使用。此外,如果我想开始新的下载,则不清楚将下载插入阵列的位置。以下可能有效:

$i = 0;
while ($i < count($downloads) - 1) {
    if (!is_object($downloads[$i])) {
        $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
        break;
    }
    $i++;
}

然而,这非常低效(并且while $i++循环是nooby)。所以,另一种方法是保留一个计数器。

function add_download($url) {
    global $downloads;
    static $download_counter;

    $download_counter++;
    $downloads[$download_counter] = new DownloaderObject($url);
}

这样可行,但我们仍然在数组中出现漏洞:

array(
  1  => DownloaderObject,
  3  => DownloaderObject,
  7  => DownloaderObject,
  13 => DownloaderObject
)
那是丑陋的。但是,这是可以接受的吗?数组是否应该“碎片整理”,即重新排列的键以消除空格?

或者我应该注意另一种程序化结构吗?我想要一个结构,我可以添加东西,删除东西,引用变量中的键,迭代等,这不是一个数组。这样的事情存在吗?

我已经编码好几年了,但这个问题在很多年里一直困扰着我,我仍然没有意识到答案。对于一些程序员来说这可能是显而易见的,但对我来说这是非常重要的。

6 个答案:

答案 0 :(得分:4)

PHP的“关联数组”的问题在于它们根本不是数组,它们是Hashmaps。有洞是完全没问题的。您也可以查看linked list,但Hashmap似乎非常适合您正在做的事情。

答案 1 :(得分:2)

维护您的下载器阵列是什么?

如果将数组封装在下载程序完成时通知的类中,则不必担心对已销毁对象的过时引用。

这个类可以在内部管理数组的组织,并为其用户提供一个看起来更像迭代器而不是数组的接口。

答案 2 :(得分:1)

“$ i ++循环”是没有用的,但只是因为如果使用for循环代码变得更清晰:

$i = 0;
while ($i < count($downloads) - 1) {
    if (!is_object($downloads[$i])) {
       $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
        break;
    }
    $i++;
}

变为

for($i=0;$i<count($downloads)-1;++$i){
    if (!is_object($downloads[$i])) {
        $downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
        break;
    }
}

答案 3 :(得分:1)

从C#角度来看,我首先想到的是你需要一个与数组不同的数据结构 - 你需要使用更高级别的数据结构来思考问题。或许队列,列表或堆栈更适合您的目的?

答案 4 :(得分:1)

对您的问题的简短回答是,PHP数组几乎用于所有内容,您很少使用其他数据结构。在数组索引中有漏洞并不需要担心。在Java等其他编程语言中,您可以选择更多样化的数据结构:集合,散列,列表,向量等。看来你还需要在Array和DownloaderObject类之间进行更密切的交互。仅仅因为对象$ download2已经“destroy()”本身,数组将保持对该对象的引用。

答案 5 :(得分:0)

这个问题的一些好的答案,反映了对答复者的相对经验。非常感谢 - 他们证明非常有教育意义。

差不多三年前我发布了这个问题。事后来看,我可以看到我在该领域的知识缺乏严重。我遇到的最大问题是我来自PHP的角度,它没有任意弹出元素的能力。这个问题的另一个答案让我发现,一个基本上优越的模型是'链表'

对于C,我写了一个blog post about linked lists,其中包含代码示例(此处发布的数量太多),但会整齐地填充原始问题的用例。

对于PHP,链接列表实现显示为here,我从未尝试过,但想象它也是处理上述问题的正确方法。

有趣的是,Python lists包含pop()方法,与PHP的array_pop()不同,它可以弹出任意元素并保持一切顺序。例如:

>>> x = ['baa', 'ram', 'ewe'] # our starting point
>>> x[1]                      # making sure element 1 is 'ram'
'ram'
>>> x.pop(1)                  # let's arbitrarily pop an element in the middle
'ram'
>>> x                         # the one we popped ('ram') is now gone
['baa', 'ewe']
>>> x[1]                      # and there are no holes: item 2 has become item 1
'ewe'