IIC2143-2020-2 / syllabus

Syllabus de IIC2143 Ingeniería de Software 2020-2
35 stars 10 forks source link

Diferencia entre fábrica y fábrica abstracta #222

Closed Aloncarrasco closed 3 years ago

Aloncarrasco commented 3 years ago

Hola, no tengo claro si este es el lugar para preguntarlo, aún así dejo la pregunta. ¿Cuál es la diferencia entre una fabrica y una fábrica abstracta? Leí la materia pero aún no lo entiendo.

daleal commented 3 years ago

Hola! No sé si ya resolviste tu duda usando otro medio, pero lo responderé de todas maneras. El Factory Method es un método dentro de una clase, cuyo objetivo es ser sobreescrito en sub-clases para retornar distintos tipos de objeto. De esta manera, la clase principal puede implementar lógica asumiendo que el Factoy Method retornará el tipo de objeto deseado, mientras que las sub-clases pueden preocuparse de implementar el método generador de objetos. Un ejemplo en Python (ojo que en la prueba deben programar en ruby) sería el siguiente:

class BoxWithButton:
    def create_button(self):
        return NormalButton()

    def render_box(self):
        button = self.create_button()

        # render
        render(button)

class BoxWithRoundedButton(BoxWithButton):
    def create_button(self):
        return RoundedButton()

# render normal box
normal_box = BoxWithButton()
normal_box.render_box()

# render rounded button box
rounded_button_box = BoxWithRoundedButton()
rounded_button_box.render_box()

Como puedes ver, normal_box usará botones del tipo NormalButton, mientras que rounded_button_box usará botones del tipo RoundedButton. Y es fácil ver que basta con sobreescribir el método create_button en cualquier subclase para poder mantener la lógica completa de BoxWithButton alterando solamente el método creador. Como la fábrica es un método, el patrón se llama Factory Method.

Por otro lado, una AbstractFactory es una clase! Está pensada para cuando tienes que crear familias de objetos, pero deseas que se puedan crear usando una única interfaz. De esta manera, existe una clase abstracta que implementa la "interfaz" que las fábricas concretas ocuparán, y cada fábrica concreta es una clase que está encargada únicamente de crear objetos. Siguiendo la línea de los botones, veamos un ejemplo!

class AbstractButtonFactory:
    def create_button(self):
        raise Exception("IMPLEMENT ME PLS")

    def create_checkbox(self):
        raise Exception("IMPLEMENT ME PLS")

class MacButtonFactory(AbstractButtonFactory):
    def create_button(self):
        return iButton()

    def create_checkbox(self):
        return iCheckBox()

class WindowsButtonFactory(AbstractButtonFactory):
    def create_button(self):
        return WindowsButton()

    def create_checkbox(self):
        return WindowsCheckBox()

class ButtonsRenderer:
    def __init__(self, button_factory):
        self.button = button_factory.create_button()
        self.checkbox = button_factory.create_checkbox()

    def render(self):
        render(self.button)
        render(self.checkbox)

# render mac buttons
mac_button_factory = MacButtonFactory()
mac_renderer = ButtonsRenderer(mac_button_factory)
mac_renderer.render()

windows_button_factory = WindowsButtonFactory()
windows_renderer = ButtonsRenderer(windows_button_factory)
windows_renderer.render()

Como puedes ver, a ButtonsRenderer realmente no le importa qué factory le llegue, siempre y cuando genere objetos con los métodos que espera que existan (por supuesto que dichos objetos deben tener entre sí una interfaz estándar, dado que luego quieres usarlos y no sabes qué son).

Si quieres aprender más de esto, te recomiendo ésta página para Factory Method y ésta página para Abstract Factory.