C++ 当类在某些情况下无法运行时,如何禁用类API?
假设我有以下几点:C++ 当类在某些情况下无法运行时,如何禁用类API?,c++,class,c++11,factory,C++,Class,C++11,Factory,假设我有以下几点: class Processor { public: void Activate(); /* some more interface functions*/ }; void main() { Processor().Activate(); } 类Processor只是提供公共接口的任何类的一个示例 问题 如果类处理器仅在满足某些条件时才可运行,该怎么办。例如,类Processor正在目录X上执行一些文件系统操作,如果目录X不存在,它将无法运行 问题
class Processor
{
public:
void Activate();
/* some more interface functions*/
};
void main()
{
Processor().Activate();
}
类Processor
只是提供公共接口的任何类的一个示例
问题
如果类处理器
仅在满足某些条件时才可运行,该怎么办。例如,类Processor
正在目录X
上执行一些文件系统操作,如果目录X
不存在,它将无法运行
问题
谁负责验证条件是否满足以及班级是否可运行
让我们将这些条件的计算封装到一个名为
Enabled()
建议1-来电者的责任
在这种情况下,类处理器的发起者负责在初始化类之前确保满足这些条件
缺点
打电话的人可能不知道情况是什么
这并不能解决更大的问题,如果我们有其他呼叫者没有验证条件呢
建议2——集体责任
在这种情况下,如果未启用类,则禁用所有公共接口函数
缺点
如果类Processor
具有众多接口功能,那么我们是否检查每个函数开头的m_ubissEnabled
的值李>
如果将来某个开发人员增强了界面,却忘记检查m_bisabled
的值,该怎么办
如果m_bisabled==false
建议3-工厂
使用处理器\u ptr=shared\u ptr;
类处理器工厂
{
静态处理器\u ptr create()
{
处理器ptr p;
p、 重置(新处理器);
如果(!p->IsEnabled())
p、 重置(空PTR);
返回p;
}
};
类处理器
{
公众:
无效激活();
bool IsEnabled();
友邦级处理器厂;
私人:
处理器();
bool m_bis启用;
};
到目前为止,这个方法是我最喜欢的,因为如果它不能运行,我们会阻止类的生成
缺点
1.也许是杀伤力过大
问题:
就最佳实践而言,以下哪项建议更可取?我们还有其他建议吗 我选择选项3,因为选项2和1很难跟踪,并且强制开发人员在执行每个函数之前始终验证活动标志。此外,您可以通过返回一个空对象来扩展选项#3,该对象实现了接口,但实际上什么也不做。我选择选项号#3,因为选项#2和#1很难跟踪,并强制开发人员在每个函数执行之前始终验证活动标志。此外,您可以通过返回一个空对象来扩展选项#3,该对象实现了接口,但实际上什么也不做。我也是#3的粉丝,就像igalk一样。但值得一提的是,这是模式的典型情况(资源获取是初始化)。
当构造函数中不满足实例创建的条件时,会引发异常:
class Processor
{
public:
Processor()
{
// based on conditions
if(!folderexist) // pseudocode
throw(cannotcreate)
}
// void Activate() not needed anymore
/* some more interface functions*/
private:
// bool m_bIsEnabled; not needed anymore
};
这是libs中已经使用异常的常见模式。我自己也没有什么问题,只要使用得当。不幸的是,我经常看到异常被用作长跳转或保存某些代码行的快捷方式。
失败可以是实例的有效状态。在本例中,IMHO最好创建实例并使用“有效”标志(案例2)。但大多数时候,创建的对象是毫无价值的,失败的信息只是创建者感兴趣的。在这种情况下,RAII可能是更好的选择。如果您不想或不能使用异常,工厂模式将以优雅的方式避免异常。我也像igalk一样喜欢#3。但值得一提的是,这是模式的典型情况(资源获取是初始化)。
当构造函数中不满足实例创建的条件时,会引发异常:
class Processor
{
public:
Processor()
{
// based on conditions
if(!folderexist) // pseudocode
throw(cannotcreate)
}
// void Activate() not needed anymore
/* some more interface functions*/
private:
// bool m_bIsEnabled; not needed anymore
};
这是libs中已经使用异常的常见模式。我自己也没有什么问题,只要使用得当。不幸的是,我经常看到异常被用作长跳转或保存某些代码行的快捷方式。
失败可以是实例的有效状态。在本例中,IMHO最好创建实例并使用“有效”标志(案例2)。但大多数时候,创建的对象是毫无价值的,失败的信息只是创建者感兴趣的。在这种情况下,RAII可能是更好的选择。如果您不希望或无法使用异常,工厂模式将以优雅的方式避免异常。实际上,根据能够检测到问题的代码,可以使用任何或所有这些策略
不过,一般来说,我不鼓励在对象中使用“enabled”或“validstate”标志。如果检测到问题,则尽管存在问题,该标志仍有机会继续(例如,忘记检查标志、忘记设置标志、不适当地忽略标志的值)。程序员是人,随着代码变得越来越复杂,犯一个很难追查的错误变得越来越容易
如果调用方检测到问题,则不应创建该对象,或者(如果该对象已存在)应销毁该对象。然后,它可以向调用者指出问题所在
如果对象本身检测到问题,那么它应该尽可能地恢复,并向调用者提供指示
无论哪种方式,这意味着,如果对象存在,它将保持有效状态,直到检测到问题,并且检测到问题将导致对象不存在
需要给出什么指示取决于问题的严重性,但包括错误代码(调用者可以忽略)和异常(必须忽略)之间的各种方法
using Processor_ptr = shared_ptr < Processor > ;
class ProcessorFactory
{
static Processor_ptr create()
{
Processor_ptr p;
p.reset(new Processor);
if (!p->IsEnabled())
p.reset(nullptr);
return p;
}
};
class Processor
{
public:
void Activate();
bool IsEnabled();
friend class ProcessorFactory;
private:
Processor();
bool m_bIsEnabled;
};
class Processor
{
public:
Processor()
{
// based on conditions
if(!folderexist) // pseudocode
throw(cannotcreate)
}
// void Activate() not needed anymore
/* some more interface functions*/
private:
// bool m_bIsEnabled; not needed anymore
};