由于设计了一个我用插件定位的框架,我已经将我的代码的一部分实现为单例。该类负责处理与我在框架内进行通信的外部程序的连接。
启用外部通信是一种运行时设置,但如果禁用,我不希望允许从框架内的模型访问它。我已经使用这里经常推荐的版本实现了它:
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,继续执行也是完全有效的,所以我不能只是中止它。
答案 0 :(得分:4)
添加公共功能
static bool IsServiceEnabled();
并在getInstance
中抛出异常,当它在ServiceEnabled == false时调用;
答案 1 :(得分:4)
实际上有很多可能性......这是列表的开头,没有特别的顺序。
<强>指针强>
class Communicator {
public:
static Communicator const* Instance(); // returns 0 if not Enabled
};
实际上可以用“更安全”的指针类型代替(如果指针为空且有人试图使用它,则断言/抛出)。
查询+投掷
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
...
答案 2 :(得分:1)
正确的行为是在遇到失败时抛出异常:
#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 ...
}
答案 3 :(得分:0)
我会再次考虑设计决策,然后可能会创建一个异常类并抛出它。这当然需要在另一端处理可能的异常。
答案 4 :(得分:0)
也许您应该将具有错误ServiceEnabled的传播者视为“有效”
要实现,您需要一个方法bool IsEnabled()
,并且您的其他方法需要检查servoce是否已启用,并且最常见的是,如果不是,则立即返回。
答案 5 :(得分:0)
如果没有启用,为什么不让类忽略所有带副作用的调用?这样您就可以调用所需的所有功能,而不必担心它是打开还是关闭。提供“IsServiceEnabled”(作为Henrik答案)以允许用户知道它是否应该进行通信。
答案 6 :(得分:0)
如果您真的希望能够在运行时打开和关闭通信,您可能需要担心用户可以在启用时保存Communicator引用这一事实,并在以后禁用它时尝试使用它。 当然,这个问题并不是单身人士所独有的 你可以引入另一层间接来处理它:
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;
}