Какую технологию сервера Вы используете и есть ли конкретный продукт, который Вы используете для аутентификации?
, Так как браузер только делает свое задание, я полагаю, что необходимо изменить вещи на стороне сервера для не возврата 401 кода статуса. Это могло быть сделано с помощью пользовательских форм аутентификации, которые просто возвращают форму снова, когда аутентификация перестала работать.
Если единственная цель попытки избавиться от синглтона - с точки зрения модульного тестирования, возможно, замена одноэлементный получатель с чем-то, что вы можете заменить в заглушке.
class QueueThreadMapBase
{
//virtual functions
};
class QeueueThreadMap : public QueueThreadMapBase
{
//your real implementation
};
class QeueueThreadMapTestStub : public QueueThreadMapBase
{
//your test implementation
};
static QueueThreadMapBase* pGlobalInstance = new QeueueThreadMap;
QueueThreadMapBase* getInstance()
{
return pGlobalInstance;
}
void setInstance(QueueThreadMapBase* pNew)
{
pGlobalInstance = pNew
}
Затем в вашем тесте просто замените реализацию карты очереди / потока. По крайней мере, это немного больше раскрывает синглтон.
Некоторые мысли по поводу решения:
Почему вам нужно ставить в очередь уведомления для наблюдателей, которые были созданы в другом потоке? Я предпочитаю, чтобы объект
просто уведомлял наблюдателей напрямую и возлагал на них бремя реализации поточно-безопасной реализации, зная, что Notified ()
может быть вызывается в любое время из другого потока. Наблюдатели знают, какие части их состояния необходимо защитить блокировками, и они могут справиться с этим лучше, чем объект
или очередь
.
Предполагая, что у вас действительно есть хороший причина сохранения очереди
, почему бы не сделать ее экземпляром? Просто выполните queue = new Queue ()
где-нибудь в main
, а затем передайте эту ссылку.
Что не так с помещением очереди внутри предметного класса? Для чего вам нужна карта?
У вас уже есть поток, считывающий из карты одиночной очереди. Вместо этого просто сделайте карту внутри предметного класса и предоставьте два метода для подписки наблюдателя:
class Subject
{
// Assume is threadsafe and all
private QueueMap queue;
void Subscribe(NotifyCallback, ThreadId)
{
// If it was created from another thread add to the map
if (ThreadId != This.ThreadId)
queue[ThreadId].Add(NotifyCallback);
}
public NotifyCallBack GetNext()
{
return queue[CallerThread.Id].Pop;
}
}
Теперь любой поток может вызвать метод GetNext, чтобы начать диспетчеризацию ... конечно, все это слишком упрощено, но это просто идея.
Примечание: Я работаю с предположением, что у вас уже есть архитектура вокруг этой модели, так что у вас уже есть группа наблюдателей, один или несколько субъектов и что потоки уже переходят на карту, чтобы делать уведомления.
Мой подход заключался в том, чтобы наблюдатели предоставляли очередь, когда они регистрируются у субъекта; владелец наблюдателя будет нести ответственность как за поток, так и за связанную очередь, а субъект будет связывать наблюдателя с очередью без необходимости в центральном реестре.
Поточно-безопасные наблюдатели могут регистрироваться без очереди и вызываться непосредственно субъектом.
Ваши наблюдатели могут быть дешевыми, но они зависят от карты потока уведомлений, очереди, верно?
Что неудобного в том, чтобы сделать эту зависимость явной и взять ее под контроль?
Что касается фабрики приложений, которую описывает Мишко Хевери В его статье самые большие преимущества заключаются в том, что 1) фабричный подход не скрывает зависимости и 2) отдельные экземпляры, от которых вы зависите, недоступны глобально, так что любой другой объект может вмешиваться в их состояние. Таким образом, используя этот подход в любом заданном контексте приложения верхнего уровня, вы точно знаете, что использует вашу карту. С глобально доступным синглтоном любой используемый вами класс может делать неприятные вещи с картой или с картой.
Как насчет добавления метода Reset, который возвращает синглтон в его начальное состояние, которое вы можете вызывать между тестами? Это может быть проще, чем заглушка. Можно было бы добавить общий метод Reset к шаблону Singleton (удаляет внутренний одноэлементный pimpl и сбрасывает указатель). Это может даже включать реестр всех синглтонов с основным методом ResetAll для их сброса!