单例
单例是一种设计模式,它的目的是确保一个类只有一个实例,并且提供全局访问点以访问该实例。
在单例模式中,类只能被实例化一次,以确保所有的对象访问都指向同一个实例。这对于需要共享状态或资源的类非常有用,并且避免了多个类实例引起的资源浪费或冲突的问题。
单例模式通常包含以下几个关键要素:
- 私有化构造函数,使得其他类无法直接实例化该类。
- 静态成员变量,用于存储类的唯一实例。
- 静态方法,用于提供全局访问该实例的接口。
由以上可知,要想实现server_socket的单例,需将server_socket写成一个类。
为什么要将服务器写为单例
- 提高性能:单例模式只会创建一个实例,因此可以避免创建多个实例时造成的资源浪费,从而提高性能。
- 简化代码:单例模式可以将服务器的初始化和配置逻辑集中到一个地方,从而简化代码。
- 提高安全性:单例模式可以避免多个实例之间共享数据,从而提高安全性。
以下是一些具体的例子:
- Web 服务器:Web 服务器通常是单例的,因为它只需要一个实例来处理所有客户端的请求。
- 数据库连接池:数据库连接池通常是单例的,因为它只需要一个实例来管理所有数据库连接。
- 日志系统:日志系统通常是单例的,因为它只需要一个实例来记录所有日志。
当然,将服务器写为单例也有一些缺点:
- 可扩展性:单例模式不利于扩展,因为它只能有一个实例。
- 可测试性:单例模式不利于测试,因为它很难模拟多个实例之间的交互。
因此,在决定是否将服务器写为单例时,需要权衡利弊。如果服务器需要高性能、简洁的代码和高安全性,那么单例模式是一个不错的选择。如果服务器需要可扩展性和可测试性,那么单例模式可能不是最佳选择。
- 确保单例模式是必要的:在决定将服务器写为单例之前,需要确保单例模式是必要的。如果服务器不需要高性能、简洁的代码和高安全性,那么单例模式可能不是最佳选择。
- 使用合适的单例模式:有两种常见的单例模式:饿汉式单例模式和懒汉式单例模式。饿汉式单例模式在类加载时就创建实例,而懒汉式单例模式在第一次使用时才创建实例。选择合适的单例模式需要根据具体情况进行判断。
- 考虑可扩展性和可测试性:单例模式不利于扩展和可测试性。在设计单例模式时,需要考虑可扩展性和可测试性。
CServerSocket类
为保证整个程序只有一个CServerSocket,所以将CServerSocket写为一个类,并将类的构造函数、析构函数、复制构造函数、赋值运算符重载都写为private。
在类中声明一个静态变量static CServerSocket* m_instance,并实现静态函数static CServerSocket* getInstance()以获取m_instance。(静态函数没有this指针,无法直接访问普通成员变量,所以将m_instance设为静态的)
class CServerSocket
{
public:
static CServerSocket* getInstance() {
if (m_instance == NULL) {//静态函数没有this指针,无法直接访问普通成员变量,所以将m_instance改为静态的
m_instance = new CServerSocket();
}
return m_instance;
}
private://私有,不允许外部复制
CServerSocket& operator=(const CServerSocket& ss) {}
CServerSocket(const CServerSocket& ss) {
m_sock = ss.m_sock;
m_client = ss.m_client;
}
CServerSocket() {
if (InitSockEnv() == FALSE) {
MessageBox(NULL, _T("无法初始化套接字环境,请检查网络设置"), _T("初始化错误"), MB_OK | MB_ICONERROR);
exit(0);
}
};
~CServerSocket() {
WSACleanup();
};
BOOL InitSockEnv() {
WSADATA data;
if (WSAStartup(MAKEWORD(1, 1), &data) != 0){
return FALSE;
}
return TRUE;
}
static CServerSocket* m_instance;
};
在主函数中调用getIntance()会报错:无法解析的外部符号。因为m_instance只是声明,没有赋初值。在CServerSocket.cpp中添加以下代码:
//置空 显式初始化
CServerSocket* CServerSocket::m_instance = NULL;
CHelper类
以上代码存在问题,即m_intance不会自动析构。
于是在CServerSocket中新建一个CHelper类,帮助m_instance进行析构。
新建releaseInstance(),用于m_instance的析构。
class CServerSocket
{
public:
static CServerSocket* getInstance() {...}
private:
CServerSocket& operator=(const CServerSocket& ss) {}
CServerSocket(const CServerSocket& ss) {...}
CServerSocket() {...};
~CServerSocket() {...};
BOOL InitSockEnv() {...}
static void releaseInstance() {
if (m_instance) {
CServerSocket* tmp = m_instance;
m_instance = NULL;
delete tmp;
}
}
static CServerSocket* m_instance;
class CHelper {
public:
CHelper() {
CServerSocket::getInstance();
}
~CHelper() {
CServerSocket::releaseInstance();
}
};
static CHelper m_helper;
};
在cpp中添加
//调用构造函数
CServerSocket::CHelper CServerSocket::m_helper;
CServerSocket* pserver = CServerSocket::getInstance();