具体示例:控制单元的抽象,它也可以是由套接字表示的远程单元。为了便于使用,我考虑在构造函数中创建套接字并接受()。
不过,这感觉有点奇怪。这样的构造函数总是会失败。它可能会阻塞。有没有一种方法不会让我感到不舒服,或者只是 OO 并且我必须服用那种药丸?
(这个问题尤其与流行的 OO 语言和那里使用的普遍接受的风格有关)
虽然锁定构造函数不一定是坏事,但我会考虑对用户隐藏它。就像是:
connection establish_connection();
从用户代码中,如果他们看到:
connection c = establish_connection();
建立连接并返回活动连接似乎是明智的。用户期望代码可能会失败(异常)或阻塞,因此不会有任何意外,因为在许多库中创建 asocket
是非阻塞调用。
注意:在这段代码中connection
代表一个活动连接,库应该控制是否connection
可以直接创建,是否可以关闭(通过析构函数以外的任何东西,即connection
对象是否可以活动而不代表活动连接)以及它是否可以复制以及语义是什么。
在 C++ 中,类模板std::lock_guard
将愉快地阻塞,直到它获得一个互斥锁:
std::mutex m;
{
std::lock_guard<std::mutex> _(m);
//...
}
这是完全合法的使用,并且是使用 SBRM 成语(“范围绑定资源管理”,以前称为“RAII”)的强烈惯用 C++。
是的,构造函数可以阻塞。经典示例是表示 RAII 互斥锁的类,在构造时获取互斥锁。该构造函数将阻塞,直到另一个线程释放互斥锁。
如果您完全accept
失败,那么您应该从构造函数中抛出异常以指示此类失败。
看看抽象工厂设计模式。您可以隐藏从它们自己的接口继承的具体类,避免您以正常方式创建实例。然后,您创建一个可以访问具体类并可以为您构建这些对象的类,例如工厂。例如:
在您的图书馆中:
//ConcreteWindow class must not be visible to the final user.
class ConcreteWindow : public AbstractWindow
{
...
};
class GUIManager
{
public:
AbstractWindow* createWindow()
{
return new ConcreteWindow();
}
...
};
在您的应用程序中:
GUIManager* gui = new GUIManager();
//ConcreteWindow class not visible.
AbstractWindow* myWindow = gui->createWindow();
在 C++ 中,您没有对类的访问修饰符,例如 Java 和 C#。但是您可以使用名称空间或标头包含(不包括)来隐藏具体类。您现在被迫“要求”您的工厂类为您创建该对象。