python,怎么用工厂模式设计代码?

hengchen / 2024-08-07 / 原文

工厂模式

打造工厂模式,需要抽象工厂和具体工厂。怎么理解?抽象工厂就是接口的定义,但不负责具体的实现。而具体工厂则需要负责定义的接口的实现。就好比你爸爸让你上街时带一瓶酱油,而具体买什么牌子的由你决定。”你爸爸让带一瓶酱油“就是接口的定义函数,这个函数只负责定义”要求“,而不负责实现,而实现是由你来做的,那你就是具体工厂、你爸爸就是抽象工厂。简单理解抽象工厂是提要求的人(其实代码里就是类class),具体工厂就是实现”要求“的人(代码类class)。

工厂模式的实现

我们现在有个任务,需要你完成一个get、post方法,进行数据和发送和接受。另外需要覆盖http、websocket、tcp三种协议。我们首先要明白虽然同样是发送数据、接受数据,但是要知道三种协议的实现方式有很大不同。如果实现都相同,也就不会产生三种协议了,对吧?

猛一听这个要求,是不是下意识觉得很困难。需要同时为http、websocket、tcp三种协议实现get、post方法,你可能会被困难吓住。而我要告诉你,实现这个一点都不难,我们使用工厂方法,对这个任务进行分解并设计,把大的困难,分解为一个个小任务,就简单了。下面我们开始做。

根据工厂模式,我们需要在具体实现前面,先去定义要求。我们的要求一共有两个,实现get、post。知道了要求,我们还知道定义要求是在抽象工厂里实现的。那就先写抽象工厂类,再把要求写到抽象工厂类里面,就算完成了。

from abc import ABCMeta, abstractmethod
#继承了metaclass=ABCMeta的类就会被python认定为抽象类
class Protocol(metaclass=ABCMeta):
    
    """@abstractmethod用来定义抽象方法,如果没有装饰符,那就是一个普通方法。
    为啥这么安排呢,这是因为一旦使用了@abstractmethod,在接下来的具体工厂里
    这个方法就会被强制要求实现,如果你不实现就会python报错。就像你不给你爸爸
    买酱油,就会挨打一样"""
    @abstractmethod
    def post(self, body):
        '''发送请求的接口'''
        #注意抽象方法不需要具体去实现,具体实现是在具体方法里完成,所以这里pass即可
        pass

    @abstractmethod
    def get(self):
        '''获取数据的接口'''
        pass

有了抽象工厂后,接下来我们就来实现具体工厂。即把post、get实现,使其真正能够发送和接受数据。

import requests
import socket
#http协议
#继承了抽象工厂Protocol,我们在实现具体方法时,必须要实现post、get,否则报错!
class HttpProtocol(Protocol):
    def __init__(self, ip):
        self._ip = ip
        
    def post(self,body):
    	http.request('POST', url, body=json.dumps(body))
	
	def get(self):
		http.get('get', url)
 #websocket协议 
 #继承了抽象工厂Protocol,我们在实现具体方法时,必须要实现post、get,否则报错!
class WebSocketProtocol(Protocol):
    def __init__(self, ip):
        self._ip = ip
        
    def post(self, body):
        if 'requestUrl' not in body:
            print('requestUrl is needed for WebSocket request')
            return False
        with self._ws_mutex:
             self._requests.append(json.dumps(body))
             print('已经发送: {}'.format(json.dumps(body)))
        return self.get_data()
      
     def get(self):
        data = self.sock.recv(4090)
        return data
	        
	      
 #tcp协议 
 #继承了抽象工厂Protocol,我们在实现具体方法时,必须要实现post、get,否则报错!
class TcpProtocol(Protocol):
	def __init__(self, ip):
        self._ip = ip
    def post(self, body):
        try:
            time.sleep(5)
            self.sock.send(body)
            print('已经发送: {}'.format(body))
        finally:
            pass

    def get(self):   '
        data = self.sock.recv(4090)
        return data
    
 

到此具体工厂已经实现了,我们可以使用HttpProtocol(ip).post(body)等去调用post、get方法了,调用时,根据具体的协议选择具体工厂,如果你需要用websocket协议进行收发,请用WebSocketProtocol(ip).post(body)。灵活使用。为了更加贴近实际的使用场景,我们对客户端代码,也使用工厂模式进行设计一下,看到这里我想我不用写,你也会设计了吧。不过为了照顾到大多数人,我还是写一下示例。

客户端针对不同的ip进行连接

#客户端抽象工厂
class TransportationFactory(metaclass=ABCMeta):
    '''传输层连接到ip'''
    #这里定义connect方法,以便符合实际场景
    @abstractmethod
    def connect(self,ip):
        '''连接到ip'''
        pass
#客户端具体工厂
class HttpTransportation(TransportationFactory):

    def connect(self,ip):
        return HttpProtocol(ip)

class WebSocketTransportation(TransportationFactory):
    def connect(self,ip):
        return WebSocketProtocol(ip)

class TcpTransportation(TransportationFactory):

    def connect(self,ip):
        return TcpProtocol(ip)
#具体使用方式
t_http = HttpTransportation().connect("192.168.1.10")
t_websocket = WebSocketTransportation().connect("192.168.1.10")
t_tcp = TcpTransportation.().connect("192.168.1.10")
body ={
  "services" : [ {
    "service_id" : "serviceId",
    "properties" : {
      "Height" : 124,
      "Speed" : 23.24
    },
    "event_time" : "2021-08-13T10:10:10.555Z"
  } ]
}
t_http.post(body)
t_websocket.post(body)
t_tcp.post(body)