Проблемы реализовывая шаблон “Наблюдателя”

Я бы, вероятно, использовал robots.txt поверх тега meta. Robots.txt существует дольше и может быть более широко поддержан (но я не уверен на 100% в этом).

Что касается второй части, я думаю, что большинство пауков примут любой наиболее ограничивающий параметр для страницы - если есть несоответствие между robots.txt и метатегом.

32
задан SadSido 19 June 2009 в 15:28
поделиться

10 ответов

Очень интересный выпуск.

Попробуйте следующее:

  1. Измените remObserver, чтобы обнулить запись, а не просто удалить ее (и сделать недействительными итераторы списка).
  2. Измените цикл notifyAll на:

    for (все зарегистрированные наблюдатели) { если (наблюдатель) наблюдатель-> уведомление (); }

  3. Добавьте еще один цикл в конец notifyAll, чтобы удалить все пустые записи из вашего списка наблюдателей

14
ответ дан 27 November 2019 в 21:05
поделиться

Определите и используйте мощный итератор над контейнером уведомителей, который устойчив к удалению (например, обнуление, как упоминалось ранее) и может обрабатывать добавление (например, добавление)

с другой стороны, если вы хотите принудительно сохранить константу контейнера во время уведомления, объявите notifyAll и контейнер, для которого выполняется итерация, как const.

0
ответ дан 27 November 2019 в 21:05
поделиться

Как насчет наличия итератора-члена с именем current (инициализированного как итератор end ). Тогда

void remObserver(Observer* obs)
{
    list<Observer*>::iterator i = observers.find(obs);
    if (i == current) { ++current; }
    observers.erase(i);
}

void notifyAll()
{
    current = observers.begin();
    while (current != observers.end())
    {
        // it's important that current is incremented before notify is called
        Observer* obs = *current++;
        obs->notify(); 
    }
}
0
ответ дан 27 November 2019 в 21:05
поделиться

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

В любом случае, из вашего описания кажется, что проблема не в параллелизме (многопоточность), а скорее в мутациях, вызванных вызовом Observer :: notify (). В этом случае вы можете решить проблему, используя вектор и обходя его через индекс, а не итератор.

for(int i = 0; i < observers.size(); ++i)
  observers[i]->notify();
0
ответ дан 27 November 2019 в 21:05
поделиться

Есть несколько решений этой проблемы:

  1. Используйте boost :: signal позволяет автоматически удалять соединение при уничтожении объекта. Но вы должны быть очень осторожны с безопасностью потоков.
  2. Используйте boost :: weak_ptr или tr1 :: weak_ptr для управления наблюдателями и boost :: поможет вам сделать объекты недействительными, weak_ptr сообщит вам, существует ли объект.
  3. Если вы выполняете какой-либо цикл событий, убедитесь, что каждый наблюдатель не уничтожить себя, добавить себя или любого другого в тот же вызов. Просто отложите задание, то есть

     SomeObserver :: notify ()
    {
     main_loop.post (boost :: bind (& SomeObserver :: someMember, это));
    }
    
3
ответ дан 27 November 2019 в 21:05
поделиться

Вот вариант уже представленной идеи TED.

Пока remObserver может обнулять запись, а не сразу удалять ее, вы можете реализовать notifyAll как:

void Subject::notifyAll()
{
    list<Observer*>::iterator i = m_Observers.begin();
    while(i != m_Observers.end())
    {
        Observer* observer = *i;
        if(observer)
        {
            observer->notify();
            ++i;
        }
        else
        {
            i = m_Observers.erase(i);
        }
    }
}

Это позволяет избежать потребность во втором цикле очистки. Однако это означает, что если какой-то конкретный вызов notify () вызывает удаление самого себя или наблюдателя, расположенного ранее в списке, то фактическое удаление элемента списка будет отложено до следующего notifyAll (). Но до тех пор, пока любые функции, которые работают со списком, должным образом проверяют наличие нулевых записей, когда это необходимо, это не должно быть проблемой.

5
ответ дан 27 November 2019 в 21:05
поделиться

Проблема в праве собственности. Вы можете использовать интеллектуальные указатели, например классы boost :: shared_ptr и boost :: weak_ptr , чтобы продлить время жизни ваших наблюдателей за пределы точки «освобождения».

4
ответ дан 27 November 2019 в 21:05
поделиться

Мужчина идет к врачу и говорит: «Док, когда я поднимаю руку как это очень больно! " Врач говорит: «Не делай этого»

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

6
ответ дан 27 November 2019 в 21:05
поделиться

Как насчет использования связанного списка в вашем цикле for ?

0
ответ дан 27 November 2019 в 21:05
поделиться

Лично я использую boost :: signal для реализации моих наблюдателей; Мне нужно будет проверить, но я считаю, что он справляется с описанными выше сценариями ( отредактировано : нашел, см. «Когда могут происходить отключения» ). Это упрощает вашу реализацию и не полагается на создание специального класса:

class Subject {
public:
   boost::signals::connection addObserver( const boost::function<void ()>& func )
   { return sig.connect(func); }

private:
   boost::signal<void ()> sig;

   void notifyAll() { sig(); }
};

void some_func() { /* impl */ }

int main() {
   Subject foo;
   boost::signals::connection c = foo.addObserver(boost::bind(&some_func));

   c.disconnect(); // remove yourself.
}
7
ответ дан 27 November 2019 в 21:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: