Al definir algoritmos, los programadores a menudo descuidan la importancia de agrupar los mismos métodos de diferentes algoritmos. Normalmente, definen algoritmos de principio a fin y repiten los mismos métodos en cada algoritmo. Esta práctica conduce a la duplicación de código y a dificultades en el mantenimiento del código; incluso para un pequeño cambio de lógica, el programador tiene que actualizar el código en varios lugares.
Un ejemplo común es la creación de autenticación mediante cuentas de redes sociales. El proceso de autenticación que usa diferentes cuentas de redes sociales es similar en general, pero varía ligeramente en el nivel de implementación. Si está definiendo los algoritmos para diferentes cuentas de principio a fin sin separar los métodos comunes, se produce la duplicación del código y las dificultades en el mantenimiento del código.
El patrón de diseño de plantilla es un patrón de diseño en Python que proporciona un patrón dedicado para evitar la duplicación de código. En este patrón de diseño, los mismos métodos se implementarán en la clase abstracta y los algoritmos que se derivan de esta clase abstracta pueden reutilizar los métodos. Tiene un método de plantilla que facilita la llamada al método para cada algoritmo derivado. Veamos los beneficios del patrón de diseño de plantilla.
- Permite que una clase controle y exponga sus partes.
- Proporciona una gran extensibilidad.
- Evita la duplicación de código
- Facilidad de mantenimiento del código
Implementación del analizador de noticias
Implementemos un analizador de noticias para obtener las últimas noticias de diferentes sitios. Aquí, consideramos RSS Feed y Atom Feed para obtener las últimas noticias. Ambos feeds se basan en el protocolo XML, con algunas diferencias en la estructura XML. Puede comprobar la estructura XML de RSS y Atom .
Aquí, nuestro patrón de diseño de plantilla consta de dos clases concretas: YahooNewsParser y GoogleNewsParser , y estas se derivan de una clase abstracta llamada AbstractNewsParser. Esta clase abstracta contiene el método de plantilla, print_latest_news() , que llama a los métodos de operación primitivos. Aquí, los métodos de operación primitivos incluyen tanto algoritmos comunes como algoritmos diferentes, en los que los algoritmos comunes se definen en la propia clase abstracta y los algoritmos diferentes se redefinen en las respectivas clases concretas.
Del diagrama anterior, está claro que los métodos de operación primitivos get_url() y parse_content() se redefinen en clases concretas respectivas. Esto se debe a que la estructura de URL y XML difiere de la del feed. Por lo tanto, es necesario redefinir estos métodos para lograr las funcionalidades requeridas. Los otros métodos primitivos como get_raw_content() y content_crop() son métodos comunes y se definen en la propia clase abstracta. El método de plantilla, print_lates_news(), es responsable de llamar a estos métodos primitivos. Entremos en la implementación del código.
Python3
import abc import urllib.request from xml.dom.minidom import parseString class AbstractNewsParser(object, metaclass=abc.ABCMeta): def __init__(self): # Restrict creating abstract class instance if self.__class__ is AbstractNewsParser: raise TypeError('Abstract class cannot be instantiated') def print_latest_news(self): """ A Template method, returns 3 latest news for every news website """ url = self.get_url() raw_content = self.get_raw_content(url) content = self.parse_content(raw_content) cropped = self.content_crop(content) for item in cropped: print('Title: ', item['title']) print('Content: ', item['content']) print('Link: ', item['link']) print('Published ', item['published']) print('Id: ', item['id']) @abc.abstractmethod def get_url(self): pass def get_raw_content(self, url): return urllib.request.urlopen(url).read() @abc.abstractmethod def parse_content(self, content): pass def content_crop(self, parsed_content, max_items=3): return parsed_content[:max_items] class YahooNewsParser(AbstractNewsParser): def get_url(self): return 'https://news.yahoo.com/rss/' def parse_content(self, raw_content): yahoo_parsed_content = [] dom = parseString(raw_content) for node in dom.getElementsByTagName('item'): yahoo_parsed_item = {} try: yahoo_parsed_item['title'] = node.getElementsByTagName('title')[0].\ childNodes[0].nodeValue except IndexError: yahoo_parsed_item['title'] = None try: yahoo_parsed_item['content'] = node.getElementsByTagName('description')[0].\ childNodes[0].nodeValue except IndexError: yahoo_parsed_item['content'] = None try: yahoo_parsed_item['link'] = node.getElementsByTagName('link')[0].\ childNodes[0].nodeValue except IndexError: yahoo_parsed_item['link'] = None try: yahoo_parsed_item['id'] = node.getElementsByTagName('guid')[0].\ childNodes[0].nodeValue except IndexError: yahoo_parsed_item['id'] = None try: yahoo_parsed_item['published'] = node.getElementsByTagName('pubDate')[0].\ childNodes[0].nodeValue except IndexError: yahoo_parsed_item['published'] = None yahoo_parsed_content.append(yahoo_parsed_item) return yahoo_parsed_content class GoogleNewsParser(AbstractNewsParser): def get_url(self): return 'https://news.google.com/atom' def parse_content(self, raw_content): google_parsed_content = [] dom = parseString(raw_content) for node in dom.getElementsByTagName('entry'): google_parsed_item = {} try: google_parsed_item['title'] = node.getElementsByTagName('title')[0].\ childNodes[0].nodeValue except IndexError: google_parsed_item['title'] = None try: google_parsed_item['content'] = node.getElementsByTagName('content')[0].\ childNodes[0].nodeValue except IndexError: google_parsed_item['content'] = None try: google_parsed_item['link'] = node.getElementsByTagName('href')[0].\ childNodes[0].nodeValue except IndexError: google_parsed_item['link'] = None try: google_parsed_item['id'] = node.getElementsByTagName('id')[0].\ childNodes[0].nodeValue except IndexError: google_parsed_item['id'] = None try: google_parsed_item['published'] = node.getElementsByTagName('title')[0].\ childNodes[0].nodeValue except IndexError: google_parsed_item['published'] = None google_parsed_content.append(google_parsed_item) return google_parsed_content class NewsParser(object): def get_latest_news(self): yahoo = YahooNewsParser() print('Yahoo: \n', yahoo.print_latest_news()) print() print() google = GoogleNewsParser() print('Google: \n', google.print_latest_news()) if __name__ == '__main__': newsParser = NewsParser() newsParser.get_latest_news()
Producción
Un patrón de diseño de plantilla proporciona la mejor solución de diseño cuando tiene un algoritmo que tiene el mismo comportamiento con un proceso de implementación diferente. Ayuda a diseñar una estructura estándar para un algoritmo de tal manera que las clases derivadas puedan redefinir los pasos sin cambiar la estructura.
Publicación traducida automáticamente
Artículo escrito por SonuGeorge y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA