Функция, возвращающая ссылку, что возвращать при сбое? - PullRequest
2 голосов
/ 14 июля 2011

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

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

class Communicator {
public: 
    static Communicator& getInstance() {
        static Communicator instance;
        return instance;
    }
    // ...
private: 
    static bool ServiceEnabled;
    // Constructors, operator=, etc ...
}

Теперь, учитывая, что ServiceEnabled равно false, я не хочу, чтобы getInstance возвращал действительный Communicator.Но так как я возвращаю ссылку, я не могу просто вернуть 0 или что-то подобное ... Каким будет правильное поведение?Обратите внимание, что совершенно правильно продолжать выполнение, даже если ServiceEnabled имеет значение false, поэтому я не могу просто прервать выполнение, если это так.

Ответы [ 7 ]

4 голосов
/ 14 июля 2011

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

Указатель

class Communicator {
public:
  static Communicator const* Instance(); // returns 0 if not Enabled
};

Это можетфактически должен быть заменен «более безопасным» типом указателя (который утверждает / выбрасывает, если указатель нулевой и кто-то пытается его использовать).

Query + Throw

class Communicator {
public:
  static bool IsEnabled();
  static Communicator const& Instance(); // throw if not Enabled
};

Нулевой объект

class Communicator {
public:
  static Communicator const& Instance(); //returns a null instance if not Enabled

  void doit() { if (!enabled) { return; } }
};

Мне лично не очень нравится последний, потому что, скрывая тот факт, что он не был включен, вы можете помешать пользователям заметить проблему на ранней стадии.,Подумайте о транзакционной системе, убежденной в том, что она зарегистрировала свои транзакции, когда отправила все на /dev/null ...

4 голосов
/ 14 июля 2011

Добавьте публичную функцию

static bool IsServiceEnabled();

и сгенерируйте исключение в getInstance, когда она вызывается, когда ServiceEnabled == false;

1 голос
/ 14 июля 2011

Правильное поведение - генерировать исключение при возникновении ошибки:

#include <stdexcept>

class Communicator {
public: 
    static Communicator& getInstance() {
        static Communicator instance;
        if (ServiceEnabled)
          return instance;
        else
          throw std::exception("Get communicator while service is not enabled");
    }
    // ...
private: 
    static bool ServiceEnabled;
    // Constructors, operator=, etc ...
}
0 голосов
/ 14 июля 2011

Если вы действительно хотите иметь возможность включать и выключать связь во время выполнения, вам может потребоваться беспокоиться о том, что пользователь может сохранить ссылку на коммуникатор, когда она включена, и попытаться использовать ее позже, когда она отключена.,Конечно, эта проблема не уникальна для синглетов.
Вы можете добавить еще один слой косвенности, чтобы справиться с ней:

class CommunicatorImpl
{
public:
    virtual bool isEnabled() const = 0;
    virtual void doSomething() = 0;
};

class CommunicatorImpl_Enabled : public CommunicatorImpl
{
    public:
        virtual bool isEnabled() const { return true; }
        virtual void doSomething()  { /* Do something... */}
};


class CommunicatorImpl_Disabled : public CommunicatorImpl
{
    public:
        virtual bool isEnabled() const { return false; }
        virtual void doSomething()  { throw CommunicationIsDisabled("SRY"); }
};



class Communicator {
public: 
    static Communicator& getInstance() {
        static Communicator instance;
        return instance;
    }

    void enable () { m_impl = &m_enabled; }
    void disable () { m_impl = &m_disabled; }
    bool isEnabled() const { return m_impl->isEnabled(); }
    void doSomething() { m_impl->doSomething(); }

private: 
    CommunicatorImpl* m_impl;
    CommunicatorImpl_Enabled m_enabled;
    CommunicatorImpl_Disabled m_disabled;
}
0 голосов
/ 14 июля 2011

Почему бы не заставить класс просто игнорировать все вызовы с побочными эффектами, если он не включен? Таким образом, вы можете вызывать все функции, которые вам нужны, и вам не нужно беспокоиться о том, включена она или нет. Предоставьте «IsServiceEnabled» (как ответ Хенрика), чтобы позволить пользователю узнать, должен ли он общаться или нет.

0 голосов
/ 14 июля 2011

Возможно, вам следует рассматривать коммуникатор с ложным ServiceEnabled как «действительный»

Для реализации вам нужен метод bool IsEnabled(), а другие ваши методы должны проверить, включен ли сервопривод, и, чаще всего, немедленно вернуться, если это не так.

0 голосов
/ 14 июля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...