Жонглирование нескольких экземпляров объекта - PullRequest
0 голосов
/ 08 декабря 2008

Этот вопрос написан на псевдо-PHP, но я действительно не возражаю против того, на каком языке я получаю ответы (кроме Ruby :-P), так как это чисто гипотетически. На самом деле, PHP, возможно, является худшим языком для такой логики. К сожалению, я никогда не делал этого раньше, поэтому не могу привести пример из реальной жизни. Поэтому гипотетические ответы вполне приемлемы.

В принципе, у меня много объектов, выполняющих задачу. Для этого примера, скажем, каждый объект является классом, который загружает файл из Интернета. Каждый объект будет загружать отдельный файл, а загрузки выполняются параллельно. Очевидно, что некоторые объекты могут закончить загрузку раньше других. Фактический сбор данных может выполняться в потоках, но это не относится к этому вопросу.

Таким образом, мы можем определить объект так:

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++ - это нуби). Итак, другой подход заключается в том, чтобы сохранить счетчик.

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 ]

4 голосов
/ 08 декабря 2008

Проблема с «ассоциативными массивами» в PHP заключается в том, что они вообще не являются массивами, а Hashmaps . Имея отверстия там прекрасно. Вы также можете посмотреть связанный список , но Hashmap кажется идеально подходящим для того, что вы делаете.

2 голосов
/ 08 декабря 2008

Что поддерживает ваш массив загрузчиков?

Если вы инкапсулируете массив в класс, который уведомляет загрузчик о его завершении, вам не придется беспокоиться об устаревших ссылках на уничтоженные объекты.

Этот класс может управлять организацией массива изнутри и предоставлять своим пользователям интерфейс, который больше похож на итератор, чем на массив.

1 голос
/ 08 декабря 2008

Короткий ответ на ваш вопрос заключается в том, что в PHP массивы используются практически для всего, и вы редко используете другие структуры данных. Наличие дырок в индексах массива не о чем беспокоиться. В других языках программирования, таких как Java, у вас есть более разнообразный набор структур данных на выбор: наборы, хэши, списки, векторы и многое другое. Похоже, что вам также необходимо иметь более тесное взаимодействие между классом Array и DownloaderObject. Только потому, что сам объект $ download2 имеет "destroy ()", массив будет поддерживать ссылку на этот объект.

1 голос
/ 08 декабря 2008

Исходя из перспективы C #, моей первой мыслью было бы, что вам нужна другая структура данных для массива - вам нужно подумать о проблеме, используя вышестоящую структуру данных. Возможно, очередь, список или стек лучше подойдут для ваших целей?

1 голос
/ 08 декабря 2008

«Циклы $ i ++» - это nooby, но только потому, что код становится намного понятнее, если вы используете цикл 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;
    }
}
0 голосов
/ 09 декабря 2008

Несколько хороших ответов на этот вопрос, которые отражают относительный опыт респондентов. Большое спасибо - они оказались очень образовательными.

Я опубликовал этот вопрос почти три года назад. Оглядываясь назад, я вижу, что мои знания в этой области были крайне недостающими. Самая большая проблема, с которой я столкнулся, заключалась в том, что я шел с точки зрения PHP, у которого нет возможности произвольно извлекать элементы. Другие ответы на этот вопрос помогли мне обнаружить, что принципиально превосходящая модель - это «связанные списки» .

Для C я написал пост в блоге о связанных списках , который содержит примеры кода (слишком много, чтобы публиковать его здесь), но аккуратно заполнит исходный вариант использования вопроса.

Для PHP, реализация связанного списка появляется здесь , что я никогда не пробовал, но представьте, что это также будет правильным способом справиться с вышеизложенным.

Интересно, что списки Python содержат метод 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'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...