失败的抽象工厂构建的最佳实践

Best practices for abstract factory construction that fails

本文关键字:最佳 工厂 抽象 失败 构建      更新时间:2023-10-16

背景

假设我们有一个抽象工厂的实现,它被调用如下:

std::string ObjectName = "An Object Name";
std::string Args = "Argument passed directly to constructor by the factory";
std::unique_ptr<MyBaseClass> MyPtr(ObjectFactory::Instance().Construct(ObjectName,Args));

工厂使用std::map"An Object Name"转换为构造函数,构造函数本身将std::string作为参数。这个想法是,用户比我更了解构造的对象,所以我应该让开,让用户将他们想要的任何信息传递给构造函数。

问题

Args正是预期的形式时,这很好,但我不知道处理duff输入的最惯用的方法。如果用户提供了无效的参数字符串,该怎么办?

我可以想到以下内容:

  • 让对象的构造函数引发异常
  • require对象提供了一个bool Validate(std::string x)方法,该方法检查x是否是有效的参数字符串
  • 让工厂使用默认的构造函数,然后调用初始化方法(这引出了一个问题:如果init方法失败了怎么办?(
  • 设置一个bool成员变量,如果为true,则表示"此对象不处于正常状态">
  • 其他一些我没有想过的选择

抛出异常。您正在构建一个对象(尽管方式与new不同(,失败是一个例外,如果可能发生,则需要进行处理。

"解决方案2"与处理此问题无关,它更像是如何确定错误输入。因此,这可能是一个可以接受的解决方案,但这与手头的问题无关。

解决方案3在出现故障时使对象处于不确定状态,这是不可接受的。

解决方案4是另一种方法,也是唯一的方法,如果你的语言中没有异常支持,但我们有。在我看来,这种情况下的异常要好得多,因为未能构造对象是一种破坏性很强的行为,应该需要替代代码或程序终止。

第一个解决方案是构造函数失败的标准解决方案。解决方案#2和#4非常容易出错(用户可能会忘记检查(解决方案#3不能解决问题

如果您正在创建一个库,或者只是编写可能在"不允许异常"环境中重复使用的代码,则可以考虑返回std::unique_ptr{nullptr}。即使它也容易出错,这也是处理施工失败的另一种标准方法。

也许最简单的方法是返回一个nullptr。

无论做什么,都不要从构造函数抛出异常(根据更有效C++中的Item#10(,因为析构函数将不会被调用。它会导致新手内存泄漏,并迫使用户担心异常处理。

我只会断言并返回一个Null对象,使用伪工厂方法实现,或者返回nullptr。