es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

POO – ¿Cómo pasar datos “hacia arriba” en la abstracción?

Me he topado con un problema al diseñar mi software.

Mi software consta de algunas clases, Bot, Website y Scraper.

Bot es la clase más abstracta, responsable de gestionar el programa a un nivel alto.

Website es una clase que contiene datos extraídos de un sitio web en particular.

Scraper es una clase que puede tener múltiples instancias por Website. Cada instancia es responsable de una parte diferente de un solo sitio web.

Scraper tiene una función scrape_data() que devuelve los datos JSON asociados al Website. Quiero pasar estos datos a Website de alguna manera, pero no encuentro una forma de hacerlo ya que Scraper se encuentra en un nivel de abstracción inferior. Aquí están las ideas que he probado:


En esta idea, Website tendría que consultar al scraper. El scraper ya está consultando al servidor, por lo que esto parece confuso e ineficiente. class Website: def __init__(self): self.scrapers = list() self.data = dict() def add_scraper(self, scraper): self.scrapers.append(scraper) def add_data(type, json): self.data[type] = json ...

El problema aquí es que el scraper no tiene conocimiento del diccionario de sitios web. No puede pasar los datos devueltos por Scraper al Website respectivo. class Bot: def __init__(self): self.scrapers = list() self.websites = dict()

¿Cómo puedo resolver mi problema? ¿Qué reglas más fundamentales o patrones de diseño se aplican a este problema para que pueda utilizarlos en el futuro?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Una posible solución a este problema es utilizar el patrón de diseño Observer. Con este patrón, la clase Website se registraría como un observador de la clase Scraper, y la clase Scraper notificaría a sus observadores (es decir, a las instancias de Website) cada vez que tenga nuevos datos que transmitir. Esto es cómo podría lucir:

    from abc import ABC, abstractmethod
    
    class Observer(ABC):
        @abstractmethod
        def update(self, scraper, data):
            pass
    
    class Scraper:
        def __init__(self, website):
            self.website = website
    
        def scrape_data(self):
            # hacer el raspado y obtener los datos en formato JSON
            data = {...}
            self.website.notify(self, data)
    
    class Website(Observer):
        def __init__(self):
            self.scrapers = []
            self.data = {}
    
        def add_scraper(self, scraper):
            self.scrapers.append(scraper)
    
        def add_data(self, scraper, json):
            self.data[scraper] = json
    
        def notify(self, scraper, data):
            self.add_data(scraper, data)
    
    ...
    # en la clase Bot:
    website = Website()
    scraper = Scraper(website)
    website.add_scraper(scraper)
    

    En esta solución, la clase Observer define la interfaz que la clase Website necesita implementar para recibir actualizaciones de las instancias de Scraper. Scraper tiene una referencia a su propia instancia de Website, y cuando tiene nuevos datos para transmitir, notifica a la instancia de Website al llamar a su método notify(). La instancia de Website luego actualiza su propio estado con los nuevos datos al llamar a su método add_data(). De esta manera, las clases Scraper y Website permanecen débilmente acopladas y pueden modificarse de forma independiente.

    Algunos consejos adicionales que pueden ayudar con el diseño de software al trabajar con programación orientada a objetos y patrones de diseño:

    • Siempre busca un acoplamiento débil entre clases, es decir, minimiza las dependencias entre ellas. Esto puede ayudar a mantener la flexibilidad y facilidad de mantenimiento.
    • Utiliza interfaces y clases abstractas para definir contratos entre clases. Esto puede facilitar el intercambio de diferentes implementaciones de una clase en particular sin afectar a sus clientes.
    • Utiliza los principios SOLID (Responsabilidad Única, Abierto/Cerrado, Sustitución de Liskov, Segregación de Interfaces, Inversión de Dependencias) como guías para escribir código limpio, mantenible y extensible.

Comments are closed.