Паттерн Абстрактная фабрика — python

Реализация паттерна абстрактная фабрика с примером на python. Начнем сразу с примера

Допустим у нас есть 2 операционные системы Mac Os и Linux, нам необходимо реализовать произвольное окно с кнопкой или кнопками в каждой из этих операционных систем. Естественно окна и кнопки в MacOs и linux выглядят по разному, так сказать имеют разные стили оформления.

Наша задача состоит в том, что бы создать универсальный интерфейс который будет создавать окно с кнопкой в не зависимости от того на какой операционной системе запущенна программа.

Т.е. функции которая будет конструировать окно с кнопкой, будет работать вне зависимости от того какое окно мы захотим создать

Для начала опишем класс абстрактной фабрики

class WindowFactory:
    @classmethod
    def create_window(cls, name):
    """Метод создания окна, возврашает класс окно"""
        return cls.Window(name)

    @classmethod
    def create_button(cls, name):
    """Метод создания кнопки, возврашает класс кнопки"""
        return cls.Button(name)

Абстрактная фабрика готова, обратите внимание на строки return cls.Window(name) и return cls.Button(name), как видите в обоих случаях мы возвращаем некий класс(cls) у которого есть подкласс Window\Button, но в настоящий момент мы не описали ни класс  Window, ни класс Button, давайте это сделаем.

Перейдем непосредственно к реализации так называемых конкретных фабрик. Создадим класс отвечающий за создания окон и кнопок в MacOs, обратите внимание класс наследуется от абстрактной фабрики:

class MacOsFactory(WindowFactory):
    class Window:
        def __init__(self, name):
            self.name = name
            self.button = []
            self.style = 'Mac Os window style'

        def add_button(self, btn):
            self.button.append(btn.name)

        def show(self):
            print( '{} - {} and {}'.format(self.name, self.style, self.button))

    class Button:
        def __init__(self, name):
            self.name = name
            self.style = 'Mac Os button style'

И тоже самое для Linux

class LinuxFactory(WindowFactory):
    class Window:
        def __init__(self, name):
            self.name = name
            self.button = []
            self.style = 'Ubuntu window style'

        def add_button(self, btn):
            self.button.append(btn.name)

        def show(self):
            print( '{} - {} and {}'.format(self.name, self.style, self.button))

    class Button:
        def __init__(self, name):
            self.name = name
            self.style = 'Ubuntu button style'

Как не сложно заметить название методов у обоих классов полностью совпадает.

Далее осталось реализовать функцию которая будет создавать окна при помощи абстрактной фабрики:

def create_dialog(factory):
    wind = factory.create_window('Form1')
    button = factory.create_button('Button1')

    wind.add_button(button)

    return wind

Данная функция принимает на вход 1-ин параметр — класс конкретной фабрики, в нашем случае это может быть класс MacOsFactory или класс LinuxFactory. Это очень важный для понимания момент поэтому, разберем по порядку, что делает функция.

Итак, допустим мы выполнили её с параметром MacOsFactory т.е.:

  1. create_dialog(MacOsFactory)
  2. В теле функции выполнится следующий код: wind = MacOsFactory.create_window(‘Form1’) , где create_window — класс метод абстрактной фабрики
  3. В свою очередь класс-метод create_window вернет в нашем случае =>  MacOsFactory.Window(‘Form1’)
  4. Экземпляр которого мы записываем в переменную wind.

Дальнейшие действия в функции аналогичны и я думаю не нуждаются в детальных пояснениях.

Теперь когда наша программа запуститься, она каким то образом определит на какой операционной системы произошел запуск, и передаст в функцию нужный параметр, для Linux => LinuxFactory для macOs => MacOsFactory.

# Допустим мы запустились на Linux
w = create_window(LinuxFactory)
w.show()

>>> Form1 - Ubuntu window style and ['Button1']