4 must-have паттерна проектирования в Python


Оглавление (нажмите, чтобы открыть):

Полезные ссылки на тему программирование (в основном Веб-разработка, Python, Django)

  • Права в Linux (chown, chmod, SUID, GUID, sticky bit, ACL, umask)

Замеряйте скорость (speedindex) Ваших сайтов на webpagetest.org

  • 4626 29 октября 2020, 05:59

Не пропустите новые записи!

Подпишитесь на цель и следите за ее достижением

Цель состоит в группе

Веб-разработка

Вы тоже можете
опубликовать свою
цель здесь

Мы поможем вам ее достичь!

инструменты

для увлекательного достижения

© 2012—2020 SmartProgress.do
Сервис достижения целей

Виджет вашей цели

Большой (450×150 px)

Маленький (250×100 px)

Чтобы вставить виджет на ваш сайт или блог, скопируйте код и внедрите его в исходный html-код вашего блога/сайта.

Только для PRO

Вы можете купить PRO аккаунт, либо получить его бесплатно, пригласив 3 друзей на SmartProgress

State Pattern in Python

I am having some issues wrapping my head around on implementing the state design pattern in Python.

I am new to Python and wrote some code to try and answer this question that was presented to me:

Write the code for a simple ATM that allows a user to insert their card, enter their PIN, request cash and eject card. Use the following object model for the system that shows the use of the State Pattern. You will need to figure what state to change to for each action.

Please see the below UML diagram for more info:

Here is my attempt below.

The biggest point of confusion for me is how do I implement it using classes? I was able to get the correct logic in place but I am struggling with the implementation using the state design pattern.

Any guidance would be greatly appreciated.

2 Answers 2

Atm shouldn’t inherit from AtmState but from nothing (or from object , doesn’t matter). It should only contain: state variable, change method to change state and for each method in AtmState a method which calls the same named method in the current state with an additional parameter named e.g. atm containing the calling Atm object (the context).

AtmState should only contain the methods without implementation (and no variables) as it is an interface in the original pattern. For Python you should make it an abstract class with abstract methods, see module abc how to do that.

Посты с тэгом программирование

[Перевод] Python в Visual Studio Code – октябрьское обновление

Мы рады сообщить о доступности октябрьского обновления расширения Python для Visual Studio Code. Вы можете загрузить расширение Python из Marketplace или установить его прямо из галереи расширений в Visual Studio Code. Если у вас уже установлено расширение Python, вы также можете получить последнее обновление, перезапустив код Visual Studio. Подробнее о поддержке Python в Visual Studio Code вы можете узнать из документации.

В этом релизе мы рассмотрели 97 проблем, в том числе нативное редактирование Jupyter Notebooks, кнопку для запуска файла Python в терминале, а также улучшения «линтинга» (linting) и импорта с помощью Python Language Server. Полный список улучшений приведен в нашем журнале изменений .

[Перевод] PEG парсеры

Несколько лет назад меня кто-то спросил имеет ли смысл превести Python на PEG-парсер (или на грамматику PEG; я не помню точно кто и когда это было). Тогда я немного посмотрел на него, но так и не пришёл к какому-либо выводу, а потому и отбросил эту тему. Недавно я узнал больше о PEG (Parsing Expression Grammars, грамматике по парсингу выражений), и теперь я думаю, что это интересная альтернатива самописному генератору парсеров, который был разработан 30 лет назад, когда только начинал работать над Python. Я назвал его «pgen», и это был, наверно, первым фрагментом кода, который я написал для Python.


  • PEG парсеры
  • Реализация PEG парсера
  • Генерация PEG парсера
  • Визуализация работы PEG парсера
  • Леворекурсивные PEG грамматики
  • Добавление экшенов в грамматику PEG
  • Реализация остальных возможностей PEG
  • PEG на Core Developer Sprin

Раскрашиваем ч/б фото с помощью Python

Одной из интересных и популярных (особенно перед разными юбилеями) задач является «раскрашивание» старых черно-белых фотографий и даже фильмов. Тема это достаточно интересная, как с математической, так и с исторической точки зрения. Мы рассмотрим реализацию этого процесса на Python, который любой желающий сможет запустить на своем домашнем ПК.

Результат работы на фото.

Для тех кому интересно, принцип работы, исходники и примеры под катом.
Читать дальше →

[Из песочницы] Как открыть ссылку в Python. Работа с WebBrowser и решение проблемы с Internet Explorer

В ходе работы на курсачом для универа столкнулся со стандартным модулем Python — WebBrowser. Через этот модуль я хотел реализовать работу голосового ассистента с дефолтным браузером, но всё пошло не так гладко как ожидалось. Давайте для начала расскажу вам что это за модуль и как он вообще работает.
Читать дальше →

Связный список на Python: Коты в коробках

И снова здравствуйте! В преддверии старта курса «Разработчик Python» подготовили для вас небольшой авторский материал о связных списках на Python.

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

Python + Keras + LSTM: делаем переводчик текстов за полчаса

В предыдущей части я рассматривал создание несложной распознавалки текста, основанной на нейронной сети. Сегодня мы применим аналогичный подход, и напишем автоматический переводчик текстов с английского на немецкий.

Для тех, кому интересно как это работает, подробности под катом.
Читать дальше →

Подборка @pythonetc, сентябрь 2020

Новая подборка советов про Python и программирование из моего авторского канала @pythonetc.

[Перевод] Новый курс по Python от Microsoft [на английском]

Вероятно, самое большое препятствие при изучении любого нового языка программирования — просто знать, с чего начать. Что важно? Что нужно знать, чтобы стать профи? Трудно исследовать документы, когда даже нет уверенности, что читаешь то, что нужно.

Возможно, вы присматриваетесь к Python. Может быть, вы привлечены из-за его популярности. Может быть, вам нравится его гибкость. Ведь с помощью Python можно создавать решения любых форм и размеров, можно погружаться в веб-разработку, упрощать жизнь с помощью автоматизаций или, возможно, создавать будущее с помощью машинного обучения.

Выбор нового языка — обычная ситуация для современных разработчиков. Времена карьеры, полностью сосредоточенной на одном языке, давно прошли.

К счастью, концепции обычно не меняются при переходе с одного языка программирования на другой. Конечно, синтаксис может быть другим, но оператор if все еще является оператором if, даже если он написан с использованием

9 лучших опенсорс находок за сентябрь 2020

Доброго Хактоберфеста, дамы и господа. Подготовил для вас подборку самых интересных находок из опенсорса за сентябрь 2020.

За полным списком новых полезных инструментов, статей и докладов можно обратиться в мой телеграм канал @OpensourceFindings (по ссылке зеркало, если не открывается оригинал).

В сегодняшнем выпуске.
Технологии внутри: Python, C, Rust, Ruby, JavaScript, Go.
Тематика: веб разработка, администрирование, инструменты разработчика.

Создание stateful навыка для Алисы на serverless функциях Яндекс.Облака и Питоне

Начнём с новостей. Вчера Яндекс.Облако анонсировало запуск сервиса бессерверных вычислений Yandex Cloud Functions. Это значит: ты пишешь только код своего сервиса (например, веб-приложения или чатбота), а Облако само создаёт и обслуживает виртуальные машины, где он запускается, и даже реплицирует их, если возрастает нагрузка. Думать вообще не надо, очень удобно. И плата идёт только за время вычислений.

Впрочем, кое-кто может вообще не платить. Это — разработчики внешних навыков Алисы, то есть встроенных в неё чатботов. Написать, захостить и зарегистрировать такой навык может любой разработчик, а с сегодняшнего дня навыки даже не надо хостить — достаточно залить их код в облако в виде той самой бессерверной функции.

Design Pattern — Strategy

Всем привет! Хочется услышать мнение со стороны о получившемся коде. Все работает, и вроде как надо, но, не знаю, 6-е чувство подсказывает, что где-то я накосячил. Делал на основе C# кода из википедии. Если кто найдет какую-либо ошибку или недочет, дайте знать! Заранее благодарю!

06.01.2020, 21:17

Python + material design под десктоп
Собственно это возможно? Какие существуют инструменты для реализации материального дизайна под.

strategy pattern
Как можно понять етот пример? а т.е. ведь метод DoAlgorithm(); не может быть вызван в этом месте.

Примеры MVC Design Pattern
где можно почитать о сабже? желательно с примерами

Delta Design — наш ответ Altium Design
Собственно сайт разработчиков: _http://www.delta-ecad.ru ( не сочтите рекламой). Импортозамещение.

You Cannot View The Design Of This Database Because Its Design Is Hidd
При открытии базы дизайнером выдает следующее сообщение. как это победить.

Использование регулярных выражений в Python для новичков

В последние годы языки общего назначения стали чаще использоваться для анализа данных. Разработчики и организации используют Python или Javascript для решения своих задач. И в этом им помогают регулярные выражения. Они — незаменимый инструмент для упорядочивания, причесывания, поиска или извлечения текстовых данных.

Все это делает регулярные выражения полезными для изучения.

4 октября 2020 – 1 марта 2020, Москва и онлайн, беcплатно

В этой статье мы рассмотрим примеры использования и применения регулярных выражений. Они часто используются программистами в различных языках — Perl, С++, Java. Мы будем использовать Python. Ближе к концу мы также посмотрим на некоторые реальные задачи, решаемые с их помощью.

Что такое регулярные выражения и как их использовать?

Говоря простым языком, регулярное выражение — это последовательность символов, используемая для поиска и замены текста в строке или файле. Как уже было упомянуто, их поддерживает множество языков общего назначения: Python, Perl, R. Так что изучение регулярных выражений рано или поздно пригодится.

Регулярные выражения используют два типа символов:

  • специальные символы: как следует из названия, у этих символов есть специальные значения. Аналогично символу * , который как правило означает «любой символ» (но в регулярных выражениях работает немного иначе, о чем поговорим ниже);
  • литералы (например: a, b, 1, 2 и т. д.).

В Python для работы с регулярными выражениями есть модуль re . Для использования его нужно импортировать:

Чаще всего регулярные выражения используются для:

  • поиска в строке;
  • разбиения строки на подстроки;
  • замены части строки.

Давайте посмотрим на методы, которые предоставляет библиотека re для этих задач. Вот наиболее часто используемые из них:

Рассмотрим их подробнее.

re.match(pattern, string):

Этот метод ищет по заданному шаблону в начале строки. Например, если мы вызовем метод match() на строке «AV Analytics AV» с шаблоном «AV», то он завершится успешно. Однако если мы будем искать «Analytics», то результат будет отрицательный. Давайте посмотрим на его работу:

Искомая подстрока найдена. Чтобы вывести ее содержимое, используем метод group() . (Мы используем «r» перед строкой шаблона, чтобы показать, что это «сырая» строка в Python).

Теперь попробуем найти «Analytics» в данной строке. Поскольку строка начинается на «AV», метод вернет None :

Также есть методы start() и end() для того, чтобы узнать начальную и конечную позицию найденной строки.

Эти методы иногда очень полезны для работы со строками.

re.search(pattern, string):

Этот метод похож на match() , но он ищет не только в начале строки. В отличие от предыдущего, search() вернет объект, если мы попытаемся найти «Analytics».

Метод search() ищет по всей строке, но возвращает только первое найденное совпадение.

re.findall(pattern, string):

Этот метод возвращает список всех найденных совпадений. У метода findall() нет ограничений на поиск в начале или конце строки. Если мы будем искать «AV» в нашей строке, он вернет все вхождения «AV». Для поиска рекомендуется использовать именно findall() , так как он может работать и как re.search() , и как re.match() .

re.split(pattern, string, [maxsplit=0]):

Этот метод разделяет строку по заданному шаблону.

В примере мы разделили слово «Analytics» по букве «y». Метод split() принимает также аргумент maxsplit со значением по умолчанию, равным 0. В данном случае он разделит строку столько раз, сколько возможно, но если указать этот аргумент, то разделение будет произведено не более указанного количества раз. Давайте посмотрим на примеры:

Мы установили параметр maxsplit равным 1, и в результате строка была разделена на две части вместо трех.

re.sub(pattern, repl, string):

Этот метод ищет шаблон в строке и заменяет его на указанную подстроку. Если шаблон не найден, строка остается неизменной.

Мастер Йода рекомендует:  PHP для чайников

re.compile(pattern, repl, string):


Мы можем собрать регулярное выражение в отдельный объект, который может быть использован для поиска. Это также избавляет от переписывания одного и того же выражения.

До сих пор мы рассматривали поиск определенной последовательности символов. Но что, если у нас нет определенного шаблона, и нам надо вернуть набор символов из строки, отвечающий определенным правилам? Такая задача часто стоит при извлечении информации из строк. Это можно сделать, написав выражение с использованием специальных символов. Вот наиболее часто используемые из них:

Оператор Описание
. Один любой символ, кроме новой строки \n.
? 0 или 1 вхождение шаблона слева
+ 1 и более вхождений шаблона слева
* 0 и более вхождений шаблона слева
\w Любая цифра или буква (\W — все, кроме буквы или цифры)
\d Любая цифра [0-9] (\D — все, кроме цифры)
\s Любой пробельный символ (\S — любой непробельный символ)
\b Граница слова
[..] Один из символов в скобках ([^..] — любой символ, кроме тех, что в скобках)
\ Экранирование специальных символов (\. означает точку или \+ — знак «плюс»)
^ и $ Начало и конец строки соответственно
От n до m вхождений ( — от 0 до m)
a|b Соответствует a или b
() Группирует выражение и возвращает найденный текст
\t, \n, \r Символ табуляции, новой строки и возврата каретки соответственно

Больше информации по специальным символам, таким как () , | и др., можно найти на странице документации: https://docs.python.org/2/library/re.html).

Теперь давайте посмотрим на примеры использования регулярных выражений.

Примеры использования регулярных выражений

Задача 1: Вернуть первое слово из строки

Сначала попробуем вытащить каждый символ (используя . )

Для того, чтобы в конечный результат не попал пробел, используем вместо . \w .

Теперь попробуем достать каждое слово (используя * или + )

И снова в результат попали пробелы, так как * означает «ноль или более символов». Для того, чтобы их убрать, используем + :

Теперь вытащим первое слово, используя ^ :

Если мы используем $ вместо ^ , то мы получим последнее слово, а не первое:

Задача 2: Вернуть первые два символа каждого слова

Вариант 1: используя \w , вытащить два последовательных символа, кроме пробельных, из каждого слова:

Вариант 2: вытащить два последовательных символа, используя символ границы слова ( \b ):

Задача 3: вернуть список доменов из списка адресов электронной почты

Давайте снова рассмотрим решение пошагово. Сначала вернем все символы после «@»:

Как видим, части «.com», «.in» и т. д. не попали в результат. Изменим наш код:

Второй вариант — вытащить только домен верхнего уровня, используя группировку — ( ) :

Задача 4: Извлечь дату из строки

Используем \d для извлечения цифр.

Для извлечения только года нам опять помогут скобки:

Задача 5: Извлечь все слова, начинающиеся на гласную

Для начала вернем все слова:

А теперь — только те, которые начинаются на определенные буквы (используя [] ):

Выше мы видим обрезанные слова «argest» и «ommunity». Для того, чтобы убрать их, используем \b для обозначения границы слова:

Также мы можем использовать ^ внутри квадратных скобок для инвертирования группы:

В результат попали слова, «начинающиеся» с пробела. Уберем их, включив пробел в диапазон в квадратных скобках:

Задача 6: Проверить телефонный номер (номер должен быть длиной 10 знаков и начинаться с 8 или 9)

У нас есть список телефонных номеров, и нам нужно проверить их, используя регулярные выражения:

Задача 7: Разбить строку по нескольким разделителям

Также мы можем использовать метод re.sub() для замены всех разделителей пробелами:

Задача 8: Извлечь информацию из html-файла

Допустим, нам надо извлечь информацию из html-файла, заключенную между

и

, кроме первого столбца с номером. Также будем считать, что html-код содержится в строке.

Пример содержимого html-файла:

Решение (если поместить содержимое файла в переменную test_str ):

Заключение


В этой статье мы узнали, что такое регулярные выражения и как их использовать, на примере библиотеки re в Python. Кроме того, мы рассмотрели наиболее часто встречающиеся задачи, в которых их можно применить.

python vs шаблоны проектирования

есть ли для питона аналог c++шного boostа - библиотека с шаблонами?

то бишь в стандартной поставке есть фабрика, стратегии и прочие паттерны?

то бишь тебе рекомендуется выполнить этот код и задуматься.

есть ли для питона аналог c++шного boostа - библиотека с шаблонами?

ну я осилил документацию из /usr/share/doc/python-2.5 и так и не понял как мне правильно поступить:
писать шаблоны проектирования самому, или не изобретать велосипед и найти подходящую либу

The Zen of Python
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea — let's do more of those!

Перечитай import this еще раз.
Ты решил осваивать python. Совсем не обязательно писать C++/Java код на питоне. так называемые "шаблоны проектирования" — от части (и значительной части) следствие убогости C++/Java. Они не настолько нужны в питоне.
Я понимаю, да. Real programmer can write Fortran in any language.

Шаблоны проектирования - это ведь именно средство проектирования
А как они в разных языках реализуются или не реализуются - это уже дело языка. Очевидно, что в питоне все типичные шаблоны проектирования можно сделать достаточно легко. Язык хорошо надстраивается и расширяется, существования AOP - хороший тому пример.
Шаблоны проектирования связаны с объектно-ориентированным проектированием и существуют в его рамках, питон ООП поддерживает. Почему же нельзя реализовать библиотеки для реализации? Неужели я буду первым таким любителем ООП.
Или концепция Питона настолько выше ООП, что ему этого не нужно, просто я ещё не заметил?

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

Шаблоны проектирования связаны с объектно-ориентированным проектированием и существуют в его рамках, питон ООП поддерживает. Почему же нельзя реализовать библиотеки для реализации? Неужели я буду первым таким любителем ООП.

а в баше есть буст?

"Шаблоны проектировния" - это тяжелое наследие Java в большей степени.

the book Design Patterns: Elements of Reusable Object-Oriented Software was published in 1994

Java is a programming language released in 1995

Я говорю не об истории (да, Design patterns - концепция 1977 года, понимаю).
Я говорю о практике, а именно - "Users of dynamic programming languages have discussed many design patterns as workarounds for the limitations of languages such as C++ and Java. . Peter Norvig, in `Design Patterns in Dynamic Programming', discusses the triviality of implementing various patterns in dynamic languages. Norvig and others have described language features that encapsulate or replace various patterns that a C++ user must implement for themselves."

ну так слово за слово. Полез в документацию, обнаружил что питон больше чем просто замена баша и мне стало любопытно.

питон является еще и более-менее полноценным функциональным языком.

то бишь ты предлагаешь заменить одну концепцию проектирования на другую, более натуральную. Как выглядит концепции питона на UML? Можешь дать только ключевые слова для поиска.

Неправильно. Примитивное определение какое-то такое: функциональный язык - это язык, в котором фукнции являются first-class objects, т.е. настолько же полнопрвными объектами, как и, скажем, числа, строки и т.п. Кстати, полноценных лямбда-функций в питоне как раз нет.
Чтобы проникнуться питоном, рекомендуется для прочтения, на вскидку:
http://python.net/

Я вот все пытаюсь разгадать этот паззл, --- что можно собрать из "модуля для автоматической распаковки архивов любой степени вложенности" и шаблонов "фабрика", "стратегии"и прочих, --- да не выходит Поведай уже общественности, какова разгадка

так называемые "шаблоны проектирования" — от части (и значительной части) следствие убогости C++/Java.

Шаблоны проектирования связаны с объектно-ориентированным проектированием

Значительная часть так называемых "шаблонов проектирования" - это борьба с тем, что C++/Java не являются полноценными функицональными языками

шаблоны проектирования - есть всегда и везде (хоть в java, хоть в python-е, хоть в bash-е а вот реализация шаблонов проектирования уже от языка к языку плавает: где-то она более громоздкая как в java, где-то менее

Не надо их тащить везде. Не надо их тащить в питон.

есть понятие "шаблон проектирование", а есть также "каноническая реализация шаблона проектирования в ООП-языке".
ты путаешь первое со вторым.
возьмем ту же самую фабрику: задача фабрики задекларировать какого вида(с поддержкой каких интерфейсов) объекты будут создаваться, но при этом скрыть что именно будет создаваться.
канонический ООП вид этого паттерна довольно громоздкий:
интерфейсы-декларации вида объекта, класс - абстрактная фабрика, классы - конкретные фабрики, конкретные классы - реализующие интерфейс.
но также есть много и не канонических реализаций:
например, первая строчка в следующем коде - это тоже фабрика:

т.к. все принципы фабрики сохраняются: результат работы этой строчки декларация того, что именно будет уметь comparer(возвращает ключ, который поддерживает сравнение при этом само создание компарера скрыто внутри строки.
из-за того, что python более гибкий язык, чем Java - понятно, что в python-е скорее будут использоваться вот такие "локальные" реализации шаблонов проектирования, но при этом сами шаблоны проектирования - никуда не денутся.

Грубо говоря, если для реализации стратегии в C# вместо интерфейса использовать делегат, можно ли считать это стратегией или уже нет?

А можно ли считать визитором поддержку multimethods на уровне языка программирования?

говорю о практике, а именно - "Users of dynamic programming languages have discussed many design patterns as workarounds for the limitations of languages such as C++ and Java. . Peter Norvig, in `Design Patterns in Dynamic Programming', discusses the triviality of implementing various patterns in dynamic languages. Norvig and others have described language features that encapsulate or replace various patterns that a C++ user must implement for themselves."

конечно, можно. это и будет стратегия.

, в котором фукнции являются first-class objects, т.е. настолько же полнопрвными объектами

Он стал функциональным от этого?

функторы в сях приплюснутых уже давно придумали. Он стал функциональным от этого?

функторы в сях приплюснутых уже давно придумали. Он стал функциональным от этого?

из-за того, что python более гибкий язык, чем Java - понятно, что в python-е скорее будут использоваться вот такие "локальные" реализации шаблонов проектирования, но при этом сами шаблоны проектирования - никуда не денутся.

в С++ даже с ООП-то есть проблемы, т.к. приходится использовать такие костыли, как smart-pointer-ы, ref-count-pointer-ы и т.д.


Одна из задач визитора как шаблона проектирования - определение конткретных типов.

в классике про визитор - как про шаблон проектирования - написано только о разделении, что должно быть две разных сущности:
одна умеет обходить элементы
а другая умеет что-то делать с каждым элементом,
ни о каких типах там речи нет.

есть понятие "шаблон проектирование", а есть также "каноническая реализация шаблона проектирования в ООП-языке"

из-за того, что python более гибкий язык, чем Java - понятно, что в python-е скорее будут использоваться вот такие "локальные" реализации шаблонов проектирования, но при этом сами шаблоны проектирования - никуда не денутся.

Но не кажется ли, что таким образом можно любую программу нарезать на паттерны, и утверждать, что она состоит только из них, пусть часто в не очень канонических реализациях?

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

Пригляделся, и понял, что не правильно я все таки пишу. Есть же чудесный шаблон Builder, че ж я раньше-то им не пользовался?
Это сразу ответ тебе, и обещанный пример для 'я.

Все, релизация которых тривиальна в динамических функциональных языках.

Есть же чудесный шаблон Builder, че ж я раньше-то им не пользовался?

Есть же чудесный шаблон Builder, че ж я раньше-то им не пользовался?

так опять же ты все сводишь к канонической реализации.
взять какой-нибудь Linq - это тоже например, типичный пример шаблона Builder

но никакой канонической реализации нет и не будет.

Согласен с этим. Но не кажется ли, что таким образом можно любую программу нарезать на паттерны, и утверждать, что она состоит только из них, пусть часто в не очень канонических реализациях?

Все, релизация которых тривиальна в динамических функциональных языках.

То есть говоришь функции: хочу составить класс из таких-то стратегий - и она тебе генерирует класс, который эти стратегии использует. Потом берёшь наследуешь от этого класса - и всё готово.

если посмотреть на паттерны проектирования, то они скорее говорят о том, как код надо поделить на части

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

ты уверен, что надо было воротить столько кода ради того, что есть лямбда-функции.

как мне правильно поступить:писать шаблоны проектирования самому

Первый попвышийся: Visitor на любом языке, где есть multiple dispatch, например CLOS.

кольцевых отношений в иерархии классов

Первый попвышийся: Visitor на любом языке, где есть multiple dispatch, например CLOS.

Circular dependencies may also cause memory leaks by preventing certain very primitive automatic garbage collectors (those that use reference counting) from deallocating unused objects.

То есть для ООП необходимо наличие сборщика мусора? Или ты считаешь, что для ООП просто необходима поддержка кольцевых отношений в иерархии классов, или я что-то не так понял.

начнем с более простого: для ООП важно уметь получить в метод(или вернуть из метода) объект/коллекцию объектов
причем раз это базовая вещь - то это должно делаться максимально простым и максимально единообразным(стандартным) способом.
как правильно вернуть объект из метода? (какой из этих способов максимально безошибочный, простой и стандартный):

Какой процент библиотек/людей использует именно этот стандартный способ?
а сколько есть вариантов для возвращения коллекции?

Сколько библиотек/людей использует именно этот стандартный способ?
а сколько есть вариантов для возвращения коллекции?

что это за ООП, если я объект из метода без гемора вернуть не могу.

что это за ООП, если я объект из метода без гемора вернуть не могу.

со скольки библиотеками это будет работать?

Какое отношение это имеет к ООП?

но использовать ООП реально можно только дома в уголке

Я в упор не понимаю, как описанные тобою недостатки и разногласия в языке относятся к ООП.

Использовать можно где и как угодно, я не вижу никаких проблем. Я в упор не понимаю, как описанные тобою проблемы языка относятся к ООП.

Мы говорим про реальные приложения, или про программы одного автора на 100 строчек?
реальное приложение - типичная ООП- задача:
необходимо написать адаптер, который из интерфейса IZzz делает интерфейс IXxx

и как это сделать? а задача-то вроде элементарнейшая.
в итоге, и получается, что на чистом C++ - писать большие ООП-приложения не возможно (большое приложение - это приложение над которым работает больше, чем одна независимая команда)
необходимы всякие доп. соглашения: типа COM/ и т.д.
кстати под *nix скорее всего именно из-за этого продвигается идея: что каждый модуль должен жить в отдельном процессе, т.к. внутри одного процесса нормально модули связать на C++ все равно не получается.

и как это сделать? а задача-то вроде элементарнейшая.

да, никакое - но лучше, чем в C++, и еще лучше, чем в C.

Я не вижу связи между термином ООП и проблемами линковки, скорости компиляции, кроссплатформенностью, и прочее, и прочее.


Ну а где же тогда "такое"? Желательно из языков, на которых вообще реально что-то разрабатывать (учитывая все факторы от наличия специалистов и так далее).

если на языке C++ на ООП писать дороже, чем без ООП на C++, или с ООП но на C# - то значит, много ООП на C++ и не будет, что мы в принципе и видим.

более такое - будет в следующем поколении языков, в котором будут убраны явные проблемы текущих языков

Я не понял, как ты посчитал, что дороже?

Я сейчас имею столько же (ООП) проблем с C#, сколько совсем недавно имел с Си++, вообще никакой разницы не чувствую.

для ООП просто необходима поддержка кольцевых отношений

Я имел ввиду что-то вроде (там плоховатая статья на эту тему, но понять идею можно) http://en.wikipedia.org/wiki/Circular_dependencies

сколько сторонних библиотек ты использовал в первом и во втором случае? в каком виде в них было ООП?

при оплате моего времени по тарифной ставке: 120$/час приведу калькуляции времени, которое тратит средний программист на поддержание ООП в C++ и на поддержание ООП в C#.

Как обычно, большой пост, который по моему субъективному мнению мало попадает в тему. Мы говорим о необходимости GC для ООП языка.

Поясни, что это за фигня, пожалуйста. А то от каждой интерпретации, приходящей мне в голову, у меня начинают шевелиться волосы по всему телу.

Причём заметь, что проблема возвращения heap-allocated объекта из метода в принципе не очень стрёмная, ну, люди это делают как-то. Напрягаясь, вспоминая текущие соглашения и глядя в описание метода каждый раз (если это хорошие программисты но делают. Я даже не буду указывать на тот очевидный факт, что подразумеваемое утверждение: "в недалёком будущем конпелятор будет оптимизировать нах весь этот десяток вызовов конструкторов копирования" дико напоминает сходные утверждения фанатов хаскеля, но применительно к плюсам обретает особую глубину ироничности. Ох, указал всё-таки.

Есть ведь и другие, гораздо более мучительно реализуемые на языке без GC вещи, например, анонимные функции. И ленивые списки, и итераторы — естественно, как first-class objects, чтобы их можно было куда-нибудь передавать. Ни один человек в здравом уме никогда не захочет руками прописывать, что функцию, переданную в map, диспозить не надо, потому что она нам здесь ещё понадобится, а функцию, повешенную на эвент, наоборот евент должен сам отдиспозить, а здесь её совсем не надо диспозить. И что надо сделать с функцией, переданной в некую функцию f, про которую конпелятор не знает.

То бишь большой проект на функциональном языке не сделаешь - неудобно делать декомпозицию без инкапсуляции.

Python Design Patterns: For Sleek And Fashionable Code

Let’s say it again: Python is a high-level programming language with dynamic typing and dynamic binding. I would describe it as a powerful, high-level dynamic language. Many developers are in love with Python because of its clear syntax, well structured modules and packages, and for its enormous flexibility and range of modern features.

In Python, nothing obliges you to write classes and instantiate objects from them. If you don’t need complex structures in your project, you can just write functions. Even better, you can write a flat script for executing some simple and quick task without structuring the code at all.

At the same time Python is a 100 percent object-oriented language. How’s that? Well, simply put, everything in Python is an object. Functions are objects, first class objects (whatever that means). This fact about functions being objects is important, so please remember it.

So, you can write simple scripts in Python, or just open the Python terminal and execute statements right there (that’s so useful!). But at the same time, you can create complex frameworks, applications, libraries and so on. You can do so much in Python. There are of course a number of limitations, but that’s not the topic of this article.

However, because Python is so powerful and flexible, we need some rules (or patterns) when programming in it. So, let see what patterns are, and how they relate to Python. We will also proceed to implement a few essential Python design patterns.

Why Is Python Good For Patterns?

Any programming language is good for patterns. In fact, patterns should be considered in the context of any given programming language. Both the patterns, language syntax and nature impose limitations on our programming. The limitations that come from the language syntax and language nature (dynamic, functional, object oriented, and the like) can differ, as can the reasons behind their existence. The limitations coming from patterns are there for a reason, they are purposeful. That’s the basic goal of patterns; to tell us how to do something and how not to do it. We’ll speak about patterns, and especially Python design patterns, later.

Python’s philosophy is built on top of the idea of well thought out best practices. Python is a dynamic language (did I already said that?) and as such, already implements, or makes it easy to implement, a number of popular design patterns with a few lines of code. Some design patterns are built into Python, so we use them even without knowing. Other patterns are not needed due of the nature of the language.

For example, Factory is a structural Python design pattern aimed at creating new objects, hiding the instantiation logic from the user. But creation of objects in Python is dynamic by design, so additions like Factory are not necessary. Of course, you are free to implement it if you want to. There might be cases where it would be really useful, but they’re an exception, not the norm.

What is so good about Python’s philosophy? Let’s start with this (explore it in the Python terminal):

These might not be patterns in the traditional sense, but these are rules that define the “Pythonic” approach to programming in the most elegant and useful fashion.

We have also PEP-8 code guidelines that help structure our code. It’s a must for me, with some appropriate exceptions, of course. By the way, these exceptions are encouraged by PEP-8 itself:

But most importantly: know when to be inconsistent – sometimes the style guide just doesn’t apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don’t hesitate to ask!

Combine PEP-8 with The Zen of Python (also a PEP - PEP-20), and you’ll have a perfect foundation to create readable and maintainable code. Add Design Patterns and you are ready to create every kind of software system with consistency and evolvability.

Python Design Patterns

What Is A Design Pattern?

Everything starts with the Gang of Four (GOF). Do a quick online search if you are not familiar with the GOF.

Design patterns are a common way of solving well known problems. Two main principles are in the bases of the design patterns defined by the GOF:

  • Program to an interface not an implementation.
  • Favor object composition over inheritance.

Let’s take a closer look at these two principles from the perspective of Python programmers.

Program to an interface not an implementation

Think about Duck Typing. In Python we don’t like to define interfaces and program classes according these interfaces, do we? But, listen to me! This doesn’t mean we don’t think about interfaces, in fact with Duck Typing we do that all the time.


Let’s say some words about the infamous Duck Typing approach to see how it fits in this paradigm: program to an interface.

We don’t bother with the nature of the object, we don’t have to care what the object is; we just want to know if it’s able to do what we need (we are only interested in the interface of the object).

Can the object quack? So, let it quack!

Did we define an interface for our duck? No! Did we program to the interface instead of the implementation? Yes! And, I find this so nice.

As Alex Martelli points out in his well known presentation about Design Patterns in Python, “Teaching the ducks to type takes a while, but saves you a lot of work afterwards!”

Favor object composition over inheritance

Now, that’s what I call a Pythonic principle! I have created fewer classes/subclasses compared to wrapping one class (or more often, several classes) in another class.

Instead of doing this:

We can do something like this:

The advantages are obvious. We can restrict what methods of the wrapped class to expose. We can inject the persister instance in runtime! For example, today it’s a relational database, but tomorrow it could be whatever, with the interface we need (again those pesky ducks).

Composition is elegant and natural to Python.

Behavioral Patterns

Behavioural Patterns involve communication between objects, how objects interact and fulfil a given task. According to GOF principles, there are a total of 11 behavioral patterns in Python: Chain of responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template, Visitor.

I find these patterns very useful, but this does not mean the other pattern groups are not.

Iterator

Iterators are built into Python. This is one of the most powerful characteristics of the language. Years ago, I read somewhere that iterators make Python awesome, and I think this is still the case. Learn enough about Python iterators and generators and you’ll know everything you need about this particular Python pattern.

Chain of responsibility

This pattern gives us a way to treat a request using different methods, each one addressing a specific part of the request. You know, one of the best principles for good code is the Single Responsibility principle.

Every piece of code must do one, and only one, thing.

This principle is deeply integrated in this design pattern.

For example, if we want to filter some content we can implement different filters, each one doing one precise and clearly defined type of filtering. These filters could be used to filter offensive words, ads, unsuitable video content, and so on.

Command

This is one of the first Python design patterns I implemented as a programmer. That reminds me: Patterns are not invented, they are discovered. They exist, we just need to find and put them to use. I discovered this one for an amazing project we implemented many years ago: a special purpose WYSIWYM XML editor. After using this pattern intensively in the code, I read more about it on some sites.

The command pattern is handy in situations when, for some reason, we need to start by preparing what will be executed and then to execute it when needed. The advantage is that encapsulating actions in such a way enables Python developers to add additional functionalities related to the executed actions, such as undo/redo, or keeping a history of actions and the like.

Let’s see what a simple and frequently used example looks like:

Creational Patterns

Let’s start by pointing out that creational patterns are not commonly used in Python. Why? Because of the dynamic nature of the language.

Someone wiser than I once said that Factory is built into Python. It means that the language itself provides us with all the flexibility we need to create objects in a sufficiently elegant fashion; we rarely need to implement anything on top, like Singleton or Factory.

In one Python Design Patterns tutorial, I found a description of the creational design patterns that stated these design “patterns provide a way to create objects while hiding the creation logic, rather than instantiating objects directly using a new operator.”

That pretty much sums up the problem: We don’t have a new operator in Python!

Nevertheless, let’s see how we can implement a few, should we feel we might gain an advantage by using such patterns.

Singleton

The Singleton pattern is used when we want to guarantee that only one instance of a given class exists during runtime. Do we really need this pattern in Python? Based on my experience, it’s easier to simply create one instance intentionally and then use it instead of implementing the Singleton pattern.

But should you want to implement it, here is some good news: In Python, we can alter the instantiation process (along with virtually anything else). Remember the __new__() method I mentioned earlier? Here we go:

In this example, Logger is a Singleton.

These are the alternatives to using a Singleton in Python:

  • Use a module.
  • Create one instance somewhere at the top-level of your application, perhaps in the config file.
  • Pass the instance to every object that needs it. That’s a dependency injection and it’s a powerful and easily mastered mechanism.

Dependency Injection


I don’t intend to get into a discussion on whether dependency injection is a design pattern, but I will say that it’s a very good mechanism of implementing loose couplings, and it helps make our application maintainable and extendable. Combine it with Duck Typing and the Force will be with you. Always.

I listed it in the creational pattern section of this post because it deals with the question of when (or even better: where) the object is created. It’s created outside. Better to say that the objects are not created at all where we use them, so the dependency is not created where it is consumed. The consumer code receives the externally created object and uses it. For further reference, please read the most upvoted answer to this Stackoverflow question.

It’s a nice explanation of dependency injection and gives us a good idea of the potential of this particular technique. Basically the answer explains the problem with the following example: Don’t get things to drink from the fridge yourself, state a need instead. Tell your parents that you need something to drink with lunch.

Python offers us all we need to implement that easily. Think about its possible implementation in other languages such as Java and C#, and you’ll quickly realize the beauty of Python.

Let’s think about a simple example of dependency injection:

We inject the authenticator and authorizer methods in the Command class. All the Command class needs is to execute them successfully without bothering with the implementation details. This way, we may use the Command class with whatever authentication and authorization mechanisms we decide to use in runtime.

We have shown how to inject dependencies through the constructor, but we can easily inject them by setting directly the object properties, unlocking even more potential:

There is much more to learn about dependency injection; curious people would search for IoC, for example.

But before you do that, read another Stackoverflow answer, the most upvoted one to this question.

Again, we just demonstrated how implementing this wonderful design pattern in Python is just a matter of using the built-in functionalities of the language.

Let’s not forget what all this means: The dependency injection technique allows for very flexible and easy unit-testing. Imagine an architecture where you can change data storing on-the-fly. Mocking a database becomes a trivial task, doesn’t it? For further information, you can check out Toptal’s Introduction to Mocking in Python.

You may also want to research Prototype, Builder and Factory design patterns.

Structural Patterns

Facade

This may very well be the most famous Python design pattern.

Imagine you have a system with a considerable number of objects. Every object is offering a rich set of API methods. You can do a lot of things with this system, but how about simplifying the interface? Why not add an interface object exposing a well thought-out subset of all API methods? A Facade!

Python Facade design pattern example:

There is no surprise, no tricks, the Car class is a Facade, and that’s all.

Adapter

If Facades are used for interface simplification, Adapters are all about altering the interface. Like using a cow when the system is expecting a duck.

Let’s say you have a working method for logging information to a given destination. Your method expects the destination to have a write() method (as every file object has, for example).

I would say it is a well written method with dependency injection, which allows for great extensibility. Say you want to log to some UDP socket instead to a file,you know how to open this UDP socket but the only problem is that the socket object has no write() method. You need an Adapter!

But why do I find adapter so important? Well, when it’s effectively combined with dependency injection, it gives us huge flexibility. Why alter our well-tested code to support new interfaces when we can just implement an adapter that will translate the new interface to the well known one?

You should also check out and master bridge and proxy design patterns, due to their similarity to adapter. Think how easy they are to implement in Python, and think about different ways you could use them in your project.

Decorator

Oh how lucky we are! Decorators are really nice, and we already have them integrated into the language. What I like the most in Python is that using it teaches us to use best practices. It’s not that we don’t have to be conscious about best practices (and design patterns, in particular), but with Python I feel like I’m following best practices, regardless. Personally, I find Python best practices are intuitive and second nature, and this is something appreciated by novice and elite developers alike.

The decorator pattern is about introducing additional functionality and in particular, doing it without using inheritance.

So, let’s check out how we decorate a method without using built-in Python functionality. Here is a straightforward example.

What is not so good here is that the execute function does much more than executing something. We are not following the single responsibility principle to the letter.

It would be good to simply write just following:

We can implement any authorization and authentication functionality in another place, in a decorator, like so:

Now the execute() method is:

  • Simple to read
  • Does only one thing (at least when looking at the code)
  • Is decorated with authentication
  • Is decorated with authorization

We write the same using Python’s integrated decorator syntax:

It is important to note that you are not limited to functions as decorators. A decorator may involve entire classes. The only requirement is that they must be callables. But we have no problem with that; we just need to define the __call__(self) method.

You may also want to take a closer look at Python’s functools module. There is much to discover there!

Conclusion

I have shown how natural and easy is to use Python’s design patterns, but I have also shown how programming in Python should be easy going, too.


“Simple is better than complex,” remember that? Maybe you have noticed that none of the design patterns is fully and formally described. No complex full-scale implementations were shown. You need to “feel” and implement them in the way that best fits your style and needs. Python is a great language and it gives you all the power you need to produce flexible and reusable code.

However, it gives you more than that. It gives you the “freedom” to write really bad code. Don’t do it! Don’t Repeat Yourself (DRY) and never write code lines longer than 80 characters. And don’t forget to use design patterns where applicable; it’s one of the best ways to learn from others and gain from their wealth of experience free of charge.

Design Patterns in Python Part 1: The Strategy Pattern

Most programmers are faced with a number of recurring problems as they write object oriented code. In an attempt to standardize the solutions to these problems, four software engineers, during the 90’s, got together and >“Design Patterns: Elements of Reusable Object-Oriented Software” aka “The Gang of Four (GoF)”. It is still the authoritative reference for everything relating to software design patterns.

In layman's terms, A Design Pattern describes a problem and a general approach to solving it.

If we use design patterns, our programs will be easily understandable and extensible by those who come after us.

Classification of Design Patterns

  1. Creational Patterns: These are concerned with creating objects
  2. Structural Patterns: These patterns describe relationship between objects
  3. Behavioral Patterns: Interaction between different objects

The Strategy Pattern

The strategy pattern (aka “The Policy Pattern) is one of the most frequently used Behavioral Pattern out there. It is also one of the simplest.

The main goal of this pattern is to enable a client class to choose between different algorithms or procedures to complete the same task. This way, different algorithms can be swapped in and out without complicating things. To do this, a number of Strategy classes are created that have the same interface and contain the implementation details of the specific algorithms.

It decouples the client class from the class that is actually implementing the details of the algorithm.

You can imitate this functionality using inheritance as long as the number of algorithms and sub >composing an object from different strategies is better than creating a complex inheritance hierarchy. This might result in a explosion of classes caused by subclassing for every possible combination of procedures or algorithms.

Example

Suppose, you have two types of ducks in your program, LoudDuck and GentleDuck. The LoudDuck >VillageDuck and ToyDuck. And GentleDuck has a subtype CityDuck.

Up until this point everything looks fine. But now, your client changes her mind and wants to you to include a new type of duck, RobotDuck. She further informs you that,

  1. RobotDuck is-a LoudDuck. That’s fine, you can just inherit from the LoudDuck >“lights-on” method like ToyDuck. Now this is the tricky part. There is no straightforward way of doing this using inheritance. You cannot inherit from ToyDuck because RobotDuck does not have a is-a relationship with ToyDuck. Even if it d >ToyDuck is-a GentleDuck and RobotDuck needs to be a LoudDuck.

It is not impossible to write the program using inheritance. However, you would have to introduce many more >ToyDuck to RobotDuck, which is even worse.

However, if you use the Strategy pattern, you can easily implement this program with minimal effort:

As you can see, we are basically taking different strategy objects and “composing” other objects by using them as the building blocks. It is similar to using different types of Lego bricks to build structures. We can do this by having the strategy objects as attributes of the Duck >main.py. The strategies and their abstract interfaces are defined in strategy.py.

One other way of doing this in Python is by implementing the strategies as functions and then passing these functions to the constructors. But using interfaces is the “standard” way of taking advantage of the Strategy Pattern.

Шаблоны проектирования в Python

Design Patterns in Python

Откройте для себя современную реализацию шаблонов проектирования в Python.

Этот курс предоставляет исчерпывающий обзор шаблонов проектирования в Python с практической точки зрения. Этот курс, в частности, охватывает шаблоны с использованием:

  • Последние версии языка программирования Python
  • Использование современных подходов к программированию: внедрение зависимостей, реактивное программирование и многое другое
  • Использование современных инструментов разработчика, таких как JetBrains PyCharm
  • Обсуждение вариаций моделей и альтернативных подходов

Этот курс содержит обзор всех шаблонов проектирования Gang of Four (GoF), как они изложены в их оригинальной книге, вместе с современными вариациями, корректировками, обсуждениями внутреннего использования шаблонов в языке.

Что такое шаблоны проектирования ?

Шаблоны проектирования - это повторно используемые решения общих проблем программирования. Они были популяризированы в книге «Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения», выпущенной в 1994 году Эриком Гаммой, Джоном Влиссидесом, Ральфом Джонсоном и Ричардом Хелмом (которые обычно известны как «Банда четырех», отсюда и аббревиатура GoF).

Оригинальная книга была написана с использованием C ++ и Smalltalk в качестве примеров, но с тех пор шаблоны проектирования были адаптированы для всех мыслимых языков программирования: C #, Java, Python и даже языков программирования, которые не являются строго объектно-ориентированными, например JavaScript.

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

Какие шаблоны охватывает этот курс?

Этот курс охватывает все шаблоны проектирования GoF. Фактически, вот полный список того, что покрыто:

  • Принципы разработки SOLID: принцип единой ответственности, принцип открытого закрытого типа, принцип подстановки Лискова, принцип сегрегации интерфейса и принцип инверсии зависимости
  • Шаблоны креационного дизайна: конструктор, фабрики (фабричный метод и абстрактная фабрика), прототип и синглтон
  • Структурные шаблоны проектирования: адаптер, мост, композит, декоратор, фасад, навесной вес и прокси
  • Поведенческие шаблоны проектирования: цепь ответственности, команда, переводчик, итератор, посредник, памятные вещи, наблюдатель, состояние, стратегия, шаблонный метод и посетитель

Для кого предназначен курс?

Этот курс предназначен для разработчиков Python, которые хотят увидеть не только учебные примеры шаблонов проектирования, но также различные варианты и приемы, которые можно применять для реализации шаблонов проектирования современным способом. Например, использование декораторов и метаклассов позволяет нам заранее упаковать определенные шаблоны для простого повторного использования.

Стиль презентации

Этот курс представлен в виде (очень большой) серии живых демонстраций, проводимых в JetBrains PyCharm и представленных с использованием движка рендеринга Kinetica. Kinetica устраняет визуальный беспорядок в среде IDE, заставляя вас сосредоточиться на коде, который отображается идеально, независимо от того, смотрите ли вы курс на большом экране или мобильный телефон.

Большинство демонстраций состоят из одного файла, поэтому вы можете скачать файл, прикрепленный к уроку, и запустить его в PyCharm, IDLE или другой IDE по вашему выбору.

Этот курс не использует диаграммы классов UML; все демонстрации сделаны через живое программирование.

Паттерны проектирования приложений Python - экземпляр должен быть доступен для большинства других экземпляров

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

Допустим, у меня есть экземпляр BusMonitor (класс для протоколирования сообщений) и другие экземпляры, которые используют этот экземпляр для протоколирования действий, например, Reactor, который анализирует входящие кадры из сетевого протокола и в зависимости от фрейма он регистрирует разные сообщения.

У меня есть один главный экземпляр, который создает BusMonitor, Reactor и несколько экземпляров. Теперь я хочу, чтобы Reactor мог использовать экземпляр BusMonitor, как я могу это сделать в соответствии с шаблонами проектирования?

Установка его как переменной для Reactor кажется уродливой для меня: self._reactor.set_busmonitor(self._busmonitor)

Я бы сделал это для каждого экземпляра, которому нужен доступ к BusMonitor. Импорт этого экземпляра кажется еще хуже.

Хотя я могу сделать BusMonitor как Singleton, я имею в виду не как Class, а как модуль, а затем импортирую этот модуль, но я хочу, чтобы вещи в классах сохраняли согласованность.

Мастер Йода рекомендует:  PHP метод explode для разбиения строки с тремя примерами PHP
Добавить комментарий