2008-12-08 7 views
0

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

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

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

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 
) 

Это некрасиво. Однако это приемлемо? Должен ли массив быть «дефрагментированным», то есть ключи перегруппированы, чтобы исключить пробелы?

Или есть другая программная структура, о которой я должен знать? Я хочу структуру, в которую я могу добавить материал, удалить материал, обратиться к ключам в переменной, прокрутить и т. Д., Что не является массивом. Существует ли такая вещь?

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

ответ

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' 
4

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

+0

Сегодня я использовал связанный список в приложении C, которое я написал, и они очень классные. Благодаря! :) –

1

"$ я ++ петлю" являюсь nooby, но только потому, что код становится более ясным, если вы используете для цикла:

$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

Спасибо. Да, я действительно знал о циклах 'for', но я никогда не могу вспомнить синтаксис, и это было действительно только для примера в любом случае. Вы можете видеть, что код более или менее работает одинаково. –

1

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

+0

В PHP есть массивы и только массивы. – eplawless

+0

Как я уже сказал, этот вопрос является абстрактным. Единственная причина, по которой я написал этот вопрос в PHP, - это то, о чем я в основном знаком.Если бы я писал приложение, которое делало что-то отдаленно похожее на это, я бы, вероятно, захотел изучить Python. –

+0

Очереди выглядят круто. От взгляда на статью Википедии о них вы нажимаете() на нее и поп() их. Есть ли способ перебирать их без pop(), используя их (и тем самым удаляя их из очереди)? –

1

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

2

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

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

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