工厂模式
概述
所谓的工厂模式, 常作为软件设计的一种, 属于是创建型模式. 他的目的是, 封装实例化对象的过程, 使创建对象的过程更加的灵活和可扩展. 工厂模式的核心思想是定义一个创建对象的接口, 但让实现这个接口的类决定实例化哪一个类. 这样, 工厂方法可以让类的实例化推迟到子类中进行.
作用
- 封装创建逻辑: 隐藏了创建对象的具体细节.
- 易于扩展: 增加新的产品对象时, 只需要扩展工厂即可, 无需修改已有的工厂代码.
- 遵循开闭原则: 对扩展开放, 对修改关闭.
示例代码
假设我们需要创建一个图形界面的应用程序, 其中包含两种按钮类型: Windows风格的按钮和Mac风格的按钮. 我们可以使用工厂模式来实现这个需求.
1. 定义接口
首先, 定义一个抽象接口Button
, 表示按钮的行为:
class Button{
public:
virtual void paint() = 0;
}
2.创建具体的产品
然后, 创建实现Button
接口的具体产品类, 分别表示不同平台的按钮:
class WindowsButton : public Button{
public:
void paint() override{
std::cout << "Painting Windows style button." << std:;endl;
}
}
class MacButton : public: Button{
public:
void paint() override{
std::cout << "Painting Mac style button." << std::endl;
}
}
3.定义工厂接口
接着, 定义一个工厂接口GUIFactory
, 他负责创建Button
对象:
class GUIFactory{
public:
virtual Button* createButton() = 0;
}
4.创建具体的工厂
根据不同的操作系统创建具体工厂类:
class WindowsFactory : public GUIFactory{
public:
Button* createButton() override{
return new WindowsButton();
}
}
class MacFactory : public GUIFactory{
public:
Button* createButton() override{
return new MacButton();
}
}
5.使用工厂
最后, 在客户端代码中, 我们可以通过传入不同的工厂来得到不同风格的按钮:
#include <iostream>
using namespace std;
//客户端代码
void useButton(GUIFactory* factory)
{
Button* button = factory->createButton();
button->paint();
delete button; // 释放资源
}
int main() {
// 使用 Windows 风格的按钮
GUIFactory* winFactory = new WindowsFactory();
useButton(winFactory);
delete winFactory;
// 使用 Mac 风格的按钮
GUIFactory* macFactory = new MacFactory();
useButton(macFactory);
delete macFactory;
return 0;
}
在这个例子中, GUIFactory
接口定义了一个创建按钮的方法, 而WindowsFactory
和MacFactory
分别实现了这个方法来创建不同风格的按钮. 客户端代码通过传入不同的工厂对象, 可以得到不同类型的按钮实例, 而不需要关心具体的创建的细节.
通过这样的方式, 如果未来需要添加新的按钮样式, 如Linux, 只需要添加一个新的具体工厂类, 而不需要修改现有的工厂或者是客户端的代码. 这样就达到了解耦的目的, 使得系统更加灵活和易于维护.
将当前的代码给之前的C/S进行创建
// 简单的工厂模式, 建造类设计模式
class Factory
{
public:
std::shared_ptr<Request> BuildRequest()
{
std::shared_ptr<Request> req = std::make_shared<Request>();
return req;
}
std::shared_ptr<Request> BuildRequest(int x, int y, char op)
{
std::shared_ptr<Request> req = std::make_shared<Request>(x, y, op);
return req;
}
std::shared_ptr<Response> BuildResponse()
{
std::shared_ptr<Response> resp = std::make_shared<Response>();
return resp;
}
std::shared_ptr<Response> BuildResponse(int result, int code)
{
std::shared_ptr<Response> resp = std::make_shared<Response>(result, code);
return resp;
}
};
模板方法模式
namespace Net_Work// 网络模块
{
const static int defaultSockfd = -1;
const static int backlog = 5;
enum{
Socket_Error = 1,
Bind_Error,
Listen_Error
};
// 封装一个基类, 用于表示一个socket接口类
// 设计模式: 使用模板方法模式, 未来不管是什么socket, 都继承这个类, 实现这些接口, 这样就可以复用这些接口, 这个流程是固定的
class Socket {
public:
virtual ~Socket(){}
virtual void CreateSocketOrDie() = 0;// 创建或者死亡
virtual void BindSocketOrDie(uint16_t port) = 0;// 绑定或者死亡
virtual void ListenSocketOrDie(int backlog) = 0;// 监听或者死亡 这个参数为listen函数的backlog参数,后续讲
virtual Socket* AcceptSocketOrDie(std::string *peerip, uint16_t *peerport) = 0;// 接受或者死亡 输出型参数, 获得远端ip和端口
virtual bool ConnectSocketOrDie(const std::string& serverip, uint16_t serverport) = 0;// 连接或者死亡
virtual int GetSocketFd() const = 0;// 获取socket文件描述符
virtual void SetSocketFd(int sockfd) = 0;// 设置socket文件描述符
virtual void CloseSocket() = 0;// 关闭socket
virtual bool Recv(std::string *buffer, int size) = 0;// 从socket接收数据, 参数是期望接收的字节数
virtual void Send(const std::string& send_str) = 0;// 从socket发送数据, 参数是发送的字符串
public:
void BuildListenSocketMethod(uint16_t port, int backlog)// 创建一个监听socket
{
CreateSocketOrDie();// 创建socket
BindSocketOrDie(port);// 绑定端口
ListenSocketOrDie(backlog);// 监听
}
bool BuildConnectSocketMethod(const std::string& serverip, uint16_t serverport)// 创建一个连接socket
{
CreateSocketOrDie();// 创建socket
return ConnectSocketOrDie(serverip, serverport);// 连接
}
void BuildNormalSocketMethod(int sockfd)// 创建一个普通socket
{
SetSocketFd(sockfd);
}
};
// 继承类Socket, 用于表示一个tcp socket
class TcpSocket : public Socket {
public:
TcpSocket(int sockfd = -1)
:_sockfd(sockfd)
{}
~TcpSocket()
{}
void CreateSocketOrDie() override
{
_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_sockfd < 0)
{
exit(Socket_Error);
}
}
void BindSocketOrDie(uint16_t port)
{
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
int n = ::bind(_sockfd, Convert(&local), sizeof(local));
if (n < 0)
{
exit(Bind_Error);
}
}
void ListenSocketOrDie(int backlog) override
{
int n = ::listen(_sockfd, backlog);
if (n < 0)
{
exit(Listen_Error);
}
}
Socket* AcceptSocketOrDie(std::string *peerip, uint16_t *peerport)
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int newsockfd = ::accept(_sockfd, Convert(&peer), &len);
if (newsockfd < 0)
{
return nullptr;
}
*peerport = ntohs(peer.sin_port);
*peerip = inet_ntoa(peer.sin_addr);
Socket* newSock = new TcpSocket(newsockfd);
return newSock;
}
bool ConnectSocketOrDie(const std::string& serverip, uint16_t serverport) override
{
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(serverport);
server.sin_addr.s_addr = inet_addr(serverip.c_str());
int n = ::connect(_sockfd, Convert(&server), sizeof(server));
if (n == 0)
{
return true;
}
return false;
}
int GetSocketFd() const override
{
return _sockfd;
}
void SetSocketFd(int sockfd) override
{
_sockfd = sockfd;
}
void CloseSocket() override
{
if (_sockfd > defaultSockfd)
{
::close(_sockfd);
}
}
bool Recv(std::string *buffer, int size) override // 从socket接收数据, 参数是期望接收的字节数
{
char inbuffer[size]; // 创建一个临时缓冲区来接收数据
int n = recv(_sockfd, inbuffer, size - 1, 0); // 从socket接收数据
if (n > 0) // 如果成功接收到数据
{
inbuffer[n] = 0; // 在接收到的数据末尾添加字符串结束符
*buffer += inbuffer; // 将接收到的数据追加到输出缓冲区
return true; // 返回true表示成功接收数据
}
else if (n == 0)// 为0对方关闭连接 < 0出错
{
return false;
}
else
{
return false;
}
}
void Send(const std::string& send_str) override
{
// 多路转接再统一讲
::send(_sockfd, send_str.c_str(), send_str.size(), 0);
}
private:
int _sockfd;
};
}