设计模式(二)

工厂模式

概述

所谓的工厂模式, 常作为软件设计的一种, 属于是创建型模式. 他的目的是, 封装实例化对象的过程, 使创建对象的过程更加的灵活和可扩展. 工厂模式的核心思想是定义一个创建对象的接口, 但让实现这个接口的类决定实例化哪一个类. 这样, 工厂方法可以让类的实例化推迟到子类中进行.

作用

  1. 封装创建逻辑: 隐藏了创建对象的具体细节.
  2. 易于扩展: 增加新的产品对象时, 只需要扩展工厂即可, 无需修改已有的工厂代码.
  3. 遵循开闭原则: 对扩展开放, 对修改关闭.

示例代码

假设我们需要创建一个图形界面的应用程序, 其中包含两种按钮类型: 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 接口定义了一个创建按钮的方法, 而WindowsFactoryMacFactory分别实现了这个方法来创建不同风格的按钮. 客户端代码通过传入不同的工厂对象, 可以得到不同类型的按钮实例, 而不需要关心具体的创建的细节.

通过这样的方式, 如果未来需要添加新的按钮样式, 如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;
	};
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温有情

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值