Паттерн моносостояние

Курс по Python ООП: https://stepik.org/a/116336

На этом занятии мы рассмотрим реализацию паттерна «Моносостояние», реализуемое на уровне классов и объектов. На примере этого паттерна я хочу вам показать, как можно в Python легко и гибко управлять локальными атрибутами экземпляров класса.

Вначале разберем саму идею «Моносостояния». Представьте, что у нас некий многопоточный процесс и в каждом потоке создается свой экземпляр класса ThreadData. Но нам бы хотелось, чтобы все они имели единые локальные свойства:

Обратите внимание, имели бы именно единые локальные свойства, а не просто одни и те же данные, то есть, их словарь __dict__ был бы одинаков для всех этих экземпляров.

Реализуется на Python это очень просто. Объявим класс и в нем пропишем приватный словарь с некоторыми начальными свойствами, которыми будет обладать каждый экземпляр (или же этот словарь может быть пустым):

class ThreadData:
    __shared_attrs = {
        'name': 'thread_1',
        'data': {},
        'id': 1,
    }
 
    def __init__(self):
        self.__dict__ = self.__shared_attrs

Затем, в инициализаторе этого класса, переопределим специальную коллекцию __dict__ на общий словарь __shared_attrs. Таким образом, коллекция __dict__ в каждом экземпляре будет ссылаться на один и тот же словарь класса __shared_attrs, а значит, все они будут иметь общие локальные свойства.

Я напомню, что список локальных свойств каждого конкретного экземпляра класса определяется словарем __dict__ и если у всех объектов он будет един, то едины окажутся и их локальные свойства.

Давайте посмотрим, как это будет работать. Создадим экземпляр класса th1:

th1 = ThreadData()

В консоли можно видеть, что автоматически были созданы свойства экземпляра: name, data и id, как раз те, что прописаны в словаре __shared_attrs.

Создадим второй экземпляр:

th2 = ThreadData()

Видим, что у него те же самые свойства по умолчанию. Причем, эти свойства воспринимаются как локальные. Поэтому, если их переопределить, например:

th2.id = 3

то изменения коснутся именно словаря __shared_attrs и все объекты класса ThreadData также изменят значение этого атрибута.

Также мы можем совершенно свободно создавать новые свойства:

th1.attr_new = 'new attr'

и оно появляется во всех экземплярах этого класса.

Вот так реализуется паттерн «Моносостояние» на языке Python. Возможно, у вас здесь остался вопрос, а где все это используется? Честно говоря, паттерн «Моносостояние» мне ни разу не приходилось применять. Я привел его здесь, так как он хорошо показывает, как гибко можно управлять поведением объектов класса за счет переопределения ссылки стандартного свойства __dict__ в каждом экземпляре, чтобы он вел на общий словарь __shared_attrs. Меняя эту коллекцию, оказывается можно существенно менять стандартное поведение экземпляров класса касательно их локальных атрибутов. Это и было целью данного занятия. Расширить ваше понимание о работе с атрибутами объектов классов. И, надеюсь, мне это удалось.

Курс по Python ООП: https://stepik.org/a/116336

Видео по теме