Accessing Web Resources using Factory Method Design Pattern in Python

A factory is a class for building other objects, where it creates and returns an object based on the passed parameters. Here, the client provides materials to the Factory class, and the Factory class creates and returns the products based on the given material. A Factory is not a design pattern, but it serves as a basis for the Factory Method Design Pattern.
Before getting into the Factory Method design pattern, let’s create a Simple Factory. In the below example, the SimpleFactory class has a static method called build_connection() to create objects based on the received parameter.
Python3
| importhttp.client fromftplib importFTP   classSimpleFactory(object):        @staticmethod    defbuild_connection(protocol):         ifprotocol =='https':             returnhttp.client.HTTPSConnection('www.python.org')         elifprotocol =='ftp':             returnFTP('ftp1.at.proftpd.org')         else:             raiseRuntimeError('Unknown protocol')   if__name__ =='__main__':        input_protocol =input('Which protocol to use? (https or ftp):')     protocol =SimpleFactory.build_connection(input_protocol)          ifinput_protocol =='https':         protocol.request("GET", "/")         resp =protocol.getresponse()         print(resp.status, resp.reason)          elifinput_protocol =='ftp':         resp =protocol.login()         print(resp)  | 
Let’s look into the output
 
Output
Here, you provide the type of protocol as an argument, and the factory class creates and returns the object based on the argument. The point to note is that object creation is not the responsibility of the client.
Factory Method Design Pattern
Factory Method Design Pattern is identical to a simple factory, but its structure is complicated compared to a simple factory structure. It has an abstract class that contains factory methods (to create objects) and operation methods (to work with created objects). And, the concrete classes that create objects are derived from the abstract class.
This pattern helps to define an interface to create an object. Here the classes that implement the interface decide which class to instantiate. Hence, the operation methods in the abstract class need not worry about object creation until the product interface is implemented.
Note: If you are a beginner, I strongly recommend you to go through the Factory Method – Python Design Patterns.
Advantages of the Factory Method Design Pattern
Let’s look into the advantages of the Factory Design Pattern. A few of them are:
- It makes code more universal
- It separates interfaces from implementation
- It reduces the complexity of code maintenance.
Accessing Web Resources Using Different Protocol
Let’s implement a program for accessing web resources using HTTP or FTP protocol. Here, we will use the site ftp.freebsd.org that allows both HTTP and FTP protocol.
 
Factory Method Design Pattern
From the above diagram, we can understand that the design has an abstract class called Connector, and two concrete classes – HTTPConnector and FTPConnector. The two concrete classes are derived from the Connector class, and the factory methods in the abstract class use these classes for product creation. Let’s look into the code below.
Python3
| importabc importurllib importurllib.error importurllib.request frombs4 importBeautifulSoup   classConnector(metaclass=abc.ABCMeta):     def__init__(self, is_secure):         self.is_secure =is_secure         self.port =self.factory_port()         self.protocol =self.factory_protocol()      @abc.abstractmethod     defcrawl(self):         pass     defscan(self, con_domain, con_path):         url =self.protocol +'://'+con_domain \               +':'+str(self.port) +con_path         print(url)         returnurllib.request.urlopen(url, timeout=10).read()      @abc.abstractmethod     deffactory_protocol(self):         pass     @abc.abstractmethod     deffactory_port(self):         pass classHTTPConnector(Connector):     """ Creates an HTTP Connector """     deffactory_protocol(self):         ifself.is_secure:             return'https'        return'http'     deffactory_port(self):         ifself.is_secure:             return'443'        return'80'     defcrawl(self, data):         """ crawls web content """        filenames =[]         soup =BeautifulSoup(data,"html.parser")         links =soup.table.findAll('a')                  forlink inlinks:             filenames.append(link['href'])         return'\n'.join(filenames)  classFTPConnector(Connector):     deffactory_protocol(self):         return'ftp'     deffactory_port(self):         return'21'     defcrawl(self, data):         # converting byte to string         data =str(data, 'utf-8')         lines =data.split('\n')         filenames =[]         forline inlines:             extract_line =line.split(None, 8)             iflen(extract_line) ==9:                 filenames.append(extract_line[-1])                          return'\n'.join(filenames)  if__name__ =="__main__":     con_domain ='ftp.freebsd.org'    con_path ='/pub/FreeBSD/'     con_protocol =input('Choose the protocol \                     (0-http, 1-ftp): ')          ifcon_protocol =='0':         is_secure =input('Use secure connection? (1-yes, 0-no):')         ifis_secure =='1':             is_secure =True        else:             is_secure =False        connector =HTTPConnector(is_secure)     else:         is_secure =False        connector =FTPConnector(is_secure)      try:         data =connector.scan(con_domain, con_path)     excepturllib.error.URLError as e:         print('Cannot access resource with this method', e)     else:         print(connector.crawl(data))          | 
In this program, we connect to a web page using the HTTP or FTP protocol. The Connector abstract class is designed to establish a connection (scan method), and as well as for crawling the pages (crawl method). In addition to this, it provides two factory methods – factory_protocol and factory_port – to deal with protocol and port address.
Let’s look into the output.
 
Output
Summary
A factory class is used to create other classes, It makes the code more universal. The factory methods in factory classes act as an interface for creating an object, thereby it separates interface from implementation. As a result, classes can implement these interface methods and can decide which class to instantiate.
 
				 
					


