🐍🧱 ООП Π² Python: ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID для Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΡ…

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ Ρ†Π΅Π»ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° SOLID, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID для Ρ€Π΅Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΈΠ½Π³Π°.

Данная ΡΡ‚Π°Ρ‚ΡŒΡ являСтся ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΎΠΌ. Автор: Leodanis Pozo Ramos. Бсылка Π½Π° ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π».

SOLID β€” это Π½Π°Π±ΠΎΡ€ ΠΈΠ· пяти ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ проСктирования, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π²Π°ΠΌ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ, Π³ΠΈΠ±ΠΊΠΈΠΉ ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ ΠΊΠΎΠ΄ Π½Π° основС Ρ…ΠΎΡ€ΠΎΡˆΠΎ спроСктированных, Ρ‡Π΅Ρ‚ΠΊΠΎ структурированных классов. Π­Ρ‚ΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΡΠ²Π»ΡΡŽΡ‚ΡΡ Ρ„ΡƒΠ½Π΄Π°ΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½ΠΎΠΉ Ρ‡Π°ΡΡ‚ΡŒΡŽ Π»ΡƒΡ‡ΡˆΠΈΡ… ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ проСктирования.

Π’ этом ΡƒΡ€ΠΎΠΊΠ΅ Π²Ρ‹:

  1. ΠŸΠΎΠΉΠΌΠ΅Ρ‚Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ Ρ†Π΅Π»ΡŒ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° SOLID.
  2. ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ ΠΊΠΎΠ΄ Python, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID.
  3. ΠŸΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚Π΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID для Ρ€Π΅Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΈΠ½Π³Π° ΠΊΠΎΠ΄Π° Python ΠΈ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ Π΅Π³ΠΎ Π΄ΠΈΠ·Π°ΠΉΠ½Π°.

На протяТСнии всСго обучСния Π²Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚Π΅ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ практичСскиС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ·Π½Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID ΠΌΠΎΠ³ΡƒΡ‚ привСсти ΠΊ созданию Ρ…ΠΎΡ€ΠΎΡˆΠΎ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ, Π³ΠΈΠ±ΠΊΠΎΠ³ΠΎ, ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ Π² сопровоТдСнии ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½ΡƒΡŽ ΠΎΡ‚Π΄Π°Ρ‡Ρƒ ΠΎΡ‚ этого руководства, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ…ΠΎΡ€ΠΎΡˆΠΎ Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ΡŒΡΡ Π² концСпциях ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ программирования Python, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ классы, интСрфСйсы ΠΈ наслСдованиС.

БСсплатный бонус: ΠΊΠ»ΠΈΠΊΠ½ΠΈΡ‚Π΅ здСсь, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π°, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ ΠΌΠΎΠ³Π»ΠΈ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ чистыС, ΡƒΠ΄ΠΎΠ±Π½Ρ‹Π΅ Π² сопровоТдСнии классы с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² SOLID Π² Python.

ΠžΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π² Python: ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID

Когда Π΄Π΅Π»ΠΎ Π΄ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Π΄ΠΎ написания классов ΠΈ проСктирования ΠΈΡ… взаимодСйствия Π² Python, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ ряду ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠΌΠΎΠ³ΡƒΡ‚ Π²Π°ΠΌ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Π»ΡƒΡ‡ΡˆΠΈΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄. Один ΠΈΠ· самых популярных ΠΈ общСпринятых Π½Π°Π±ΠΎΡ€ΠΎΠ² стандартов ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ проСктирования (ООП) извСстСн ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID.

Если Π²Ρ‹ ΠΏΠ΅Ρ€Π΅ΡˆΠ»ΠΈ с C++ ΠΈΠ»ΠΈ Java, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π²Ρ‹ ΡƒΠΆΠ΅ Π·Π½Π°ΠΊΠΎΠΌΡ‹ с этими ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ°ΠΌΠΈ. Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π²Π°ΠΌ интСрСсно, ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌΡ‹ Π»ΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID ΠΊ ΠΊΠΎΠ΄Ρƒ Python. ΠžΡ‚Π²Π΅Ρ‚ Π½Π° этот вопрос β€” Ρ‚Π²Π΅Ρ€Π΄ΠΎΠ΅ Π΄Π°. Если Π²Ρ‹ ΠΏΠΈΡˆΠ΅Ρ‚Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, Π²Π°ΠΌ слСдуСт ΠΏΠΎΠ΄ΡƒΠΌΠ°Ρ‚ΡŒ ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠΈ этих ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² ΠΊ Π²Π°ΡˆΠ΅ΠΌΡƒ ООП.

Но Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ эти SOLID ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹? SOLID β€” это Π°Π±Π±Ρ€Π΅Π²ΠΈΠ°Ρ‚ΡƒΡ€Π°, ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‰Π°Ρ ΠΏΡΡ‚ΡŒ основных ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ², ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌΡ‹Ρ… ΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΌΡƒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ. Π­Ρ‚ΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ Π·Π°ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ΡΡ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ:

  1. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ СдинствСнной отвСтствСнности (SRP)
  2. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ открытости/закрытости (OCP)
  3. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ подстановки Лисков (LSP)
  4. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ раздСлСния интСрфСйса (ISP)
  5. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ инвСрсии зависимостСй (DIP)

Π’Ρ‹ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚Π΅ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· этих ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² ΠΈ Π½Π°ΠΏΠΈΡˆΠΈΡ‚Π΅ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π½Π° Python. Π’ процСссС Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Ρ‡Π΅Ρ‚ΠΊΠΎΠ΅ прСдставлСниС ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ простой, ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ, ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ ΠΈ ΠΏΡ€ΠΈΠ³ΠΎΠ΄Π½Ρ‹ΠΉ для ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ использования ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, примСняя ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID. Для Π½Π°Ρ‡Π°Π»Π° Π²Ρ‹ Π½Π°Ρ‡Π½Π΅Ρ‚Π΅ с ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° Π² спискС.

1. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ СдинствСнной отвСтствСнности (SRP)

ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ СдинствСнной отвСтствСнности (SRP) Π±Ρ‹Π» Π²Π²Π΅Π΄Π΅Π½ Π ΠΎΠ±Π΅Ρ€Ρ‚ΠΎΠΌ Π‘. ΠœΠ°Ρ€Ρ‚ΠΈΠ½ΠΎΠΌ, Π±ΠΎΠ»Π΅Π΅ извСстным ΠΏΠΎΠ΄ своим ΠΏΡ€ΠΎΠ·Π²ΠΈΡ‰Π΅ΠΌ Дядя Π‘ΠΎΠ±, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ являСтся ΡƒΠ²Π°ΠΆΠ°Π΅ΠΌΠΎΠΉ Ρ„ΠΈΠ³ΡƒΡ€ΠΎΠΉ Π² ΠΌΠΈΡ€Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ³ΠΎ обСспСчСния ΠΈ ΠΎΠ΄Π½ΠΈΠΌ ΠΈΠ· ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, ΠΊΡ‚ΠΎ подписал ΠœΠ°Π½ΠΈΡ„Π΅ΡΡ‚ Agile. ЀактичСски ΠΎΠ½ Π²Π²Π΅Π» Ρ‚Π΅Ρ€ΠΌΠΈΠ½ SOLID.

ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ Π΅Π΄ΠΈΠ½ΠΎΠΉ отвСтствСнности гласит: Ρƒ класса Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Π° ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π° для измСнСния.

Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Ρƒ класса Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Π° ΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²Π΅Π½Π½ΠΎΡΡ‚ΡŒ, выраТСнная Ρ‡Π΅Ρ€Π΅Π· Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. Если класс занимаСтся Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ ΠΎΠ΄Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡Π΅ΠΉ, Π²Π°ΠΌ слСдуСт Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ эти Π·Π°Π΄Π°Ρ‡ΠΈ Π½Π° ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ классы.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
Π’Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Ρ‚Π°ΠΌ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ Ρ„ΠΎΡ€ΠΌΡƒΠ»ΠΈΡ€ΠΎΠ²ΠΊΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² SOLID. Π’ этом руководствС Π²Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚Π΅ ΡΡΡ‹Π»Π°Ρ‚ΡŒΡΡ Π½Π° Π½ΠΈΡ… Π² соотвСтствии с Ρ„ΠΎΡ€ΠΌΡƒΠ»ΠΈΡ€ΠΎΠ²ΠΊΠΎΠΉ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ дядя Π‘ΠΎΠ± ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π² своСй ΠΊΠ½ΠΈΠ³Π΅ Agile Software Development: Principles, Patterns, and Practices. Π˜Ρ‚Π°ΠΊ, всС прямыС Ρ†ΠΈΡ‚Π°Ρ‚Ρ‹ взяты ΠΈΠ· этой ΠΊΠ½ΠΈΠ³ΠΈ.

Если Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ Ρ„ΠΎΡ€ΠΌΡƒΠ»ΠΈΡ€ΠΎΠ²ΠΊΠΈ Π² ΠΊΡ€Π°Ρ‚ΠΊΠΎΠΌ ΠΎΠ±Π·ΠΎΡ€Π΅ этих ΠΈ связанных с Π½ΠΈΠΌΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ², ΠΎΠ·Π½Π°ΠΊΠΎΠΌΡŒΡ‚Π΅ΡΡŒ с Β«ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ°ΠΌΠΈ OODΒ» дяди Π‘ΠΎΠ±Π°.

Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ тСсно связан с ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠ΅ΠΉ раздСлСния Π·Π°Π΄Π°Ρ‡, которая ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ свои ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π½Π° Ρ€Π°Π·Π΄Π΅Π»Ρ‹. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·Π΄Π΅Π» Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΊΠ°ΡΠ°Ρ‚ΡŒΡΡ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ Π΅Π΄ΠΈΠ½ΠΎΠΉ отвСтствСнности ΠΈ Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π²Π°ΠΌ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Π΄ΠΈΠ·Π°ΠΉΠ½, ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ρƒ вас Π΅ΡΡ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ класс FileManager:

# file_manager_srp.py

from pathlib import Path
from zipfile import ZipFile

class FileManager:
    def __init__(self, filename):
        self.path = Path(filename)

    def read(self, encoding="utf-8"):
        return self.path.read_text(encoding)

    def write(self, data, encoding="utf-8"):
        self.path.write_text(data, encoding)

    def compress(self):
        with ZipFile(self.path.with_suffix(".zip"), mode="w") as archive:
            archive.write(self.path)

    def decompress(self):
        with ZipFile(self.path.with_suffix(".zip"), mode="r") as archive:
            archive.extractall()

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Ρƒ вашСго класса FileManager Π΄Π²Π΅ Ρ€Π°Π·Π½Ρ‹Π΅ обязанности. Он ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ .read()ΠΈ .write() для управлСния Ρ„Π°ΠΉΠ»ΠΎΠΌ. Он Ρ‚Π°ΠΊΠΆΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с ZIP-Π°Ρ€Ρ…ΠΈΠ²Π°ΠΌΠΈ, прСдоставляя ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ .compress() ΠΈ .decompress().

Π­Ρ‚ΠΎΡ‚ класс Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ СдинствСнной отвСтствСнности, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Ρƒ Π½Π΅Π³ΠΎ Π΅ΡΡ‚ΡŒ Π΄Π²Π΅ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Ρ‹ для измСнСния Π΅Π³ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΉ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ. Π§Ρ‚ΠΎΠ±Ρ‹ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ваш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π±ΠΎΠ»Π΅Π΅ Π½Π°Π΄Π΅ΠΆΠ½Ρ‹ΠΌ, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ класс Π½Π° Π΄Π²Π° ΠΌΠ΅Π½ΡŒΡˆΠΈΡ…, Π±ΠΎΠ»Π΅Π΅ Ρ†Π΅Π»Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π½Ρ‹Ρ… класса, ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΈΠΌΠ΅Π΅Ρ‚ свою спСцифику:

# file_manager_srp.py

from pathlib import Path
from zipfile import ZipFile

class FileManager:
    def __init__(self, filename):
        self.path = Path(filename)

    def read(self, encoding="utf-8"):
        return self.path.read_text(encoding)

    def write(self, data, encoding="utf-8"):
        self.path.write_text(data, encoding)

class ZipFileManager:
    def __init__(self, filename):
        self.path = Path(filename)

    def compress(self):
        with ZipFile(self.path.with_suffix(".zip"), mode="w") as archive:
            archive.write(self.path)

    def decompress(self):
        with ZipFile(self.path.with_suffix(".zip"), mode="r") as archive:
            archive.extractall()

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Ρƒ вас Π΅ΡΡ‚ΡŒ Π΄Π²Π° ΠΌΠ΅Π½ΡŒΡˆΠΈΡ… класса, Ρƒ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π΅ΡΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Π° ΠΎΠ±ΡΠ·Π°Π½Π½ΠΎΡΡ‚ΡŒ. FileManager заботится ΠΎΠ± ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ Ρ„Π°ΠΉΠ»ΠΎΠΌ, Π° ZipFileManager ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ сТатиС ΠΈ распаковку Ρ„Π°ΠΉΠ»Π° с использованиСм Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° ZIP. Π­Ρ‚ΠΈ Π΄Π²Π° класса мСньшС, поэтому ΠΈΠΌΠΈ Π»Π΅Π³Ρ‡Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ. Π˜Ρ… Ρ‚Π°ΠΊΠΆΠ΅ Π»Π΅Π³Ρ‡Π΅ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΎΡ‚Π»Π°ΠΆΠΈΠ²Π°Ρ‚ΡŒ.

ΠŸΠΎΠ½ΡΡ‚ΠΈΠ΅ отвСтствСнности Π² этом контСкстС ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ довольно ΡΡƒΠ±ΡŠΠ΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ. НаличиС Π΅Π΄ΠΈΠ½ΠΎΠΉ отвСтствСнности Π½Π΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ Π΅Π΄ΠΈΠ½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°. ΠžΡ‚Π²Π΅Ρ‚ΡΡ‚Π²Π΅Π½Π½ΠΎΡΡ‚ΡŒ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ связана Π½Π΅ с количСством ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ², Π° с основной Π·Π°Π΄Π°Ρ‡Π΅ΠΉ, Π·Π° ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ ваш класс, Π² зависимости ΠΎΡ‚ вашСго прСдставлСния ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ класс прСдставляСт Π² вашСм ΠΊΠΎΠ΄Π΅. Однако эта ΡΡƒΠ±ΡŠΠ΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° ΠΌΠ΅ΡˆΠ°Ρ‚ΡŒ Π²Π°ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ SRP.

🐍 Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° питониста
Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° питониста»
πŸπŸŽ“ Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° собСса ΠΏΠΎ Python
ΠŸΠΎΠ΄Ρ‚ΡΠ½ΡƒΡ‚ΡŒ свои знания ΠΏΠΎ Python Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° собСса ΠΏΠΎ PythonΒ»
🐍🧩 Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Π·Π°Π΄Π°Ρ‡ ΠΏΠΎ Python
Π˜Π½Ρ‚Π΅Ρ€Π΅ΡΠ½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ ΠΏΠΎ Python для ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Π·Π°Π΄Π°Ρ‡ ΠΏΠΎ PythonΒ»

2. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ открытости-закрытости (OCP)

ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ открытости-закрытости (OCP) для ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ проСктирования Π±Ρ‹Π» ΠΏΠ΅Ρ€Π²ΠΎΠ½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π²Π²Π΅Π΄Π΅Π½ Π‘Π΅Ρ€Ρ‚Ρ€Π°Π½ΠΎΠΌ ΠœΠ΅ΠΉΠ΅Ρ€ΠΎΠΌ Π² 1988 Π³ΠΎΠ΄Ρƒ ΠΈ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ:

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½Ρ‹Π΅ сущности (классы, ΠΌΠΎΠ΄ΡƒΠ»ΠΈ, Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ Ρ‚. Π΄.) Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ для Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ, Π½ΠΎ Π·Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹ для ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ открытости-закрытости, рассмотрим ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ класс Shape:

# shapes_ocp.py

from math import pi

class Shape:
    def __init__(self, shape_type, **kwargs):
        self.shape_type = shape_type
        if self.shape_type == "rectangle":
            self.width = kwargs["width"]
            self.height = kwargs["height"]
        elif self.shape_type == "circle":
            self.radius = kwargs["radius"]

    def calculate_area(self):
        if self.shape_type == "rectangle":
            return self.width * self.height
        elif self.shape_type == "circle":
            return pi * self.radius**2

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ Shape ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ shape_type, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π»ΠΈΠ±ΠΎ rectangle, Π»ΠΈΠ±ΠΎ circle. Он Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ³ΠΎ слова, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ синтаксис **kwargs. Если Π²Ρ‹ установитС Ρ‚ΠΈΠΏ Ρ„ΠΎΡ€ΠΌΡ‹ Π½Π° rectangle, Ρ‚ΠΎ Π²Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ³ΠΎ слова width ΠΈ height, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ ΠΌΠΎΠ³Π»ΠΈ ΠΏΠΎΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊ.

Напротив, Ссли для Ρ‚ΠΈΠΏΠ° Ρ„ΠΎΡ€ΠΌΡ‹ Π·Π°Π΄Π°Π½ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ circle, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ radius для построСния ΠΊΡ€ΡƒΠ³Π°.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ нСсколько ΡΠΊΡΡ‚Ρ€Π΅ΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΌ. Π•Π³ΠΎ Ρ†Π΅Π»ΡŒ состоит Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ‡Π΅Ρ‚ΠΊΠΎ Ρ€Π°ΡΠΊΡ€Ρ‹Ρ‚ΡŒ ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ идСю ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° открытости-закрытости.

Shape Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ .calculate_area(), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ вычисляСт ΠΏΠ»ΠΎΡ‰Π°Π΄ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ Ρ„ΠΎΡ€ΠΌΡ‹ Π² соотвСтствии с Π΅Π΅ .shape_type:

>>> from shapes_ocp import Shape

>>> rectangle = Shape("rectangle", width=10, height=5)
>>> rectangle.calculate_area()
50
>>> circle = Shape("circle", radius=5)
>>> circle.calculate_area()
78.53981633974483

Класс Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΊΡ€ΡƒΠ³ΠΈ ΠΈ ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠΈ, Π²Ρ‹Ρ‡ΠΈΡΠ»ΡΡ‚ΡŒ ΠΈΡ… ΠΏΠ»ΠΎΡ‰Π°Π΄ΡŒ ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅. Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, класс выглядит довольно ΠΏΠ»ΠΎΡ…ΠΎ. Π§Ρ‚ΠΎ-Ρ‚ΠΎ с Π½ΠΈΠΌ Π½Π΅ Ρ‚Π°ΠΊ Π½Π° ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ взгляд.

ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅, Ρ‡Ρ‚ΠΎ Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ„ΠΈΠ³ΡƒΡ€Ρƒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚. Как Π±Ρ‹ Π²Ρ‹ это сдСлали? Π§Ρ‚ΠΎ ΠΆ, Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ здСсь состоит Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ ΠΏΡƒΠ½ΠΊΡ‚ elif ΠΊ .__init__() ΠΈ ΠΊ .calculate_area(), Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ ΠΌΠΎΠ³Π»ΠΈ ΡƒΠ΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΠΈΡ‚ΡŒ трСбования ΠΊ ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚Π½ΠΎΠΉ Ρ„ΠΎΡ€ΠΌΠ΅.

ΠΠ΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ внСсСния этих ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ для создания Π½ΠΎΠ²Ρ‹Ρ… Ρ„ΠΈΠ³ΡƒΡ€ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ваш класс ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ для ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ. Π­Ρ‚ΠΎ Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ открытости-закрытости. Как Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ свой класс, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π΅Π³ΠΎ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ для Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ, Π½ΠΎ Π·Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ для ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ? Π’ΠΎΡ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅:

# shapes_ocp.py

from abc import ABC, abstractmethod
from math import pi

class Shape(ABC):
    def __init__(self, shape_type):
        self.shape_type = shape_type

    @abstractmethod
    def calculate_area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        super().__init__("circle")
        self.radius = radius

    def calculate_area(self):
        return pi * self.radius**2

class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("rectangle")
        self.width = width
        self.height = height

    def calculate_area(self):
        return self.width * self.height

class Square(Shape):
    def __init__(self, side):
        super().__init__("square")
        self.side = side

    def calculate_area(self):
        return self.side**2

Π’ этом ΠΊΠΎΠ΄Π΅ Π²Ρ‹ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Ρ€Π΅ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ класс Shape, ΠΏΡ€Π΅Π²Ρ€Π°Ρ‚ΠΈΠ² Π΅Π³ΠΎ Π² абстрактный Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ класс (ABC). Π­Ρ‚ΠΎΡ‚ класс прСдоставляСт Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΉ интСрфСйс (API) для любой Ρ„ΠΎΡ€ΠΌΡ‹, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ. Π­Ρ‚ΠΎΡ‚ интСрфСйс состоит ΠΈΠ· Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π° .shape_type ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° .calculate_area(), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π²ΠΎ всСх подклассах.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΈ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ… Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… Ρ€Π°Π·Π΄Π΅Π»Π°Ρ… ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ абстрактныС Π±Π°Π·ΠΎΠ²Ρ‹Π΅ классы Python для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Ρ‚Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ³ΠΎ наслСдования интСрфСйса. Π’ этом Ρ‚ΠΈΠΏΠ΅ наслСдования подклассы Π½Π°ΡΠ»Π΅Π΄ΡƒΡŽΡ‚ интСрфСйсы, Π° Π½Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ. Напротив, ΠΊΠΎΠ³Π΄Π° классы Π½Π°ΡΠ»Π΅Π΄ΡƒΡŽΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, Π²Π°ΠΌ прСдоставляСтся наслСдованиС Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ.

Π­Ρ‚ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π·Π°ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ класс для ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΉ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΠΎΡ€ΠΌΡ‹ Π² Π΄ΠΈΠ·Π°ΠΉΠ½ вашСго класса Π±Π΅Π· нСобходимости ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹ Shape. Π’ любом случаС Π²Π°ΠΌ придСтся Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΡ‹ΠΉ интСрфСйс, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ сдСлаСт ваши классы ΠΏΠΎΠ»ΠΈΠΌΠΎΡ€Ρ„Π½Ρ‹ΠΌΠΈ.

3. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ подстановки Лисков (LSP)

ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ подстановки Лисков (LSP) Π±Ρ‹Π» прСдставлСн Π‘Π°Ρ€Π±Π°Ρ€ΠΎΠΉ Лисков Π½Π° ΠΊΠΎΠ½Ρ„Π΅Ρ€Π΅Π½Ρ†ΠΈΠΈ OOPSLA Π² 1987 Π³ΠΎΠ΄Ρƒ. Π‘ Ρ‚Π΅Ρ… ΠΏΠΎΡ€ этот ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ являСтся Ρ„ΡƒΠ½Π΄Π°ΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½ΠΎΠΉ Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ программирования. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ гласит, Ρ‡Ρ‚ΠΎ: ΠΏΠΎΠ΄Ρ‚ΠΈΠΏΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ взаимозамСняСмыми для своих Π±Π°Π·ΠΎΠ²Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ².

НапримСр, Ссли Ρƒ вас Π΅ΡΡ‚ΡŒ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с классом Shape, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ этот класс Π»ΡŽΠ±Ρ‹ΠΌ ΠΈΠ· Π΅Π³ΠΎ подклассов, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Circle ΠΈΠ»ΠΈ Rectangle, Π±Π΅Π· Π½Π°Ρ€ΡƒΡˆΠ΅Π½ΠΈΡ ΠΊΠΎΠ΄Π°.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΊΠΎΠ½Ρ„Π΅Ρ€Π΅Π½Ρ†ΠΈΠΈ ΠΈΠ· основного Π΄ΠΎΠΊΠ»Π°Π΄Π°, Π³Π΄Π΅ Π‘Π°Ρ€Π±Π°Ρ€Π° Лисков Π²ΠΏΠ΅Ρ€Π²Ρ‹Π΅ подСлилась этим ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠΌ, ΠΈΠ»ΠΈ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ ΠΈΠ½Ρ‚Π΅Ρ€Π²ΡŒΡŽ с Π½Π΅ΠΉ для большСго контСкста.

На ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ этот ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ваши подклассы вСсти сСбя ΠΊΠ°ΠΊ ΠΈΡ… Π±Π°Π·ΠΎΠ²Ρ‹Π΅ классы, Π½Π΅ Π½Π°Ρ€ΡƒΡˆΠ°Ρ Ρ‡ΡŒΠΈΡ…-Π»ΠΈΠ±ΠΎ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠΉ, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ ΠΎΠ΄Π½ΠΈ ΠΈ Ρ‚Π΅ ΠΆΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°ΠΌΠΈ, связанными с Ρ„ΠΈΠ³ΡƒΡ€Π°ΠΌΠΈ, ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ρƒ вас Π΅ΡΡ‚ΡŒ класс, Rectangle, ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌΡƒ:

# shapes_lsp.py

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def calculate_area(self):
        return self.width * self.height

Π’ Rectangle Π΅ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ .calculate_area(), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π°ΠΌΠΈ экзСмпляра .width ΠΈ .height.

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚ β€” это частный случай ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠ° с Ρ€Π°Π²Π½Ρ‹ΠΌΠΈ сторонами, Π²Ρ‹ Π΄ΡƒΠΌΠ°Π΅Ρ‚Π΅ ΠΎ создании класса Square ΠΈΠ· Rectangle для ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ использования ΠΊΠΎΠ΄Π°. Π—Π°Ρ‚Π΅ΠΌ Π²Ρ‹ пСрСопрСдСляСтС ΠΌΠ΅Ρ‚ΠΎΠ΄ setter для Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ² .width ΠΈ .height Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ ΠΎΠ΄Π½ΠΎΠΉ стороны измСнялась ΠΈ другая сторона:

# shapes_lsp.py

# ...

class Square(Rectangle):
    def __init__(self, side):
        super().__init__(side, side)

    def __setattr__(self, key, value):
        super().__setattr__(key, value)
        if key in ("width", "height"):
            self.__dict__["width"] = value
            self.__dict__["height"] = value

Π’ этом Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π΅ ΠΊΠΎΠ΄Π° Π²Ρ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Square ΠΊΠ°ΠΊ подкласс Rectangle. Как ΠΈ слСдовало ΠΎΠΆΠΈΠ΄Π°Ρ‚ΡŒ, конструктор класса ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π² качСствС Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ сторону ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚Π°. Π’Π½ΡƒΡ‚Ρ€ΠΈ .__init__() ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹ .width ΠΈ .height с Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠΌ side.

Π’Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄, .__setattr__(), для ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΡƒ установки Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ² Python ΠΈ ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Π° присвоСния Π½ΠΎΠ²ΠΎΠ³ΠΎ значСния Π»ΡŽΠ±ΠΎΠΌΡƒ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρƒ .width ΠΈΠ»ΠΈ .height. Π’ частности ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ устанавливаСтС ΠΎΠ΄ΠΈΠ½ ΠΈΠ· этих Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ², для Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π° Ρ‚Π°ΠΊΠΆΠ΅ устанавливаСтся Ρ‚ΠΎ ΠΆΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:

>>> from shapes_lsp import Square

>>> square = Square(5)
>>> vars(square)
{'width': 5, 'height': 5}

>>> square.width = 7
>>> vars(square)
{'width': 7, 'height': 7}

>>> square.height = 9
>>> vars(square)
{'width': 9, 'height': 9}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ ΡƒΠ²Π΅Ρ€Π΅Π½Ρ‹, Ρ‡Ρ‚ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Square всСгда остаСтся допустимым ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚ΠΎΠΌ, облСгчая Π²Π°ΡˆΡƒ Тизнь Π·Π° Π½Π΅Π±ΠΎΠ»ΡŒΡˆΡƒΡŽ ΠΏΠ»Π°Ρ‚Ρƒ Π² Π²ΠΈΠ΄Π΅ нСбольшого количСства ΠΏΠΎΡ‚Ρ€Π°Ρ‡Π΅Π½Π½ΠΎΠΉ Π²ΠΏΡƒΡΡ‚ΡƒΡŽ памяти. К соТалСнию, это Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ подстановки Лисков, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ экзСмпляры Rectangle ΠΈΡ… Π°Π½Π°Π»ΠΎΠ³Π°ΠΌΠΈ Square.

Когда ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΠΎΠΆΠΈΠ΄Π°Π΅Ρ‚ Π² своСм ΠΊΠΎΠ΄Π΅ ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ вСсти сСбя ΠΊΠ°ΠΊ ΠΎΠ΄ΠΈΠ½, прСдоставляя Π΄Π²Π° нСзависимых Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π° .width ΠΈ .height. Π’Π΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ ваш класс Square Ρ€Π°Π·Ρ€ΡƒΡˆΠ°Π΅Ρ‚ это ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, измСняя ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅, ΠΎΠ±Π΅Ρ‰Π°Π½Π½ΠΎΠ΅ интСрфСйсом ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹Π΅ ΠΈ Π½Π΅ΠΆΠ΅Π»Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ послСдствия, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅, вСроятно, Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ ΠΎΡ‚Π»Π°Π΄ΠΈΡ‚ΡŒ.

Π₯отя ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚ β€” это особый Ρ‚ΠΈΠΏ ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠ° Π² ΠΌΠ°Ρ‚Π΅ΠΌΠ°Ρ‚ΠΈΠΊΠ΅, классы, ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΠ΅ эти Ρ„ΠΈΠ³ΡƒΡ€Ρ‹, Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π½Π°Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒΡΡ Π² ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΡΡ… Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ-ΠΏΠΎΡ‚ΠΎΠΌΠΎΠΊ, Ссли Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΈ соотвСтствовали ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡƒ подстановки Лисков. Один ΠΈΠ· способов Ρ€Π΅ΡˆΠΈΡ‚ΡŒ эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ β€” ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ класс для Rectangle ΠΈ Square для Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ:

# shapes_lsp.py

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def calculate_area(self):
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def calculate_area(self):
        return self.width * self.height

class Square(Shape):
    def __init__(self, side):
        self.side = side

    def calculate_area(self):
        return self.side ** 2

Shape становится Ρ‚ΠΈΠΏΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΠΎΠ»ΠΈΠΌΠΎΡ€Ρ„ΠΈΠ·ΠΌΠ° Π½Π° Rectangle ΠΈΠ»ΠΈ Square, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹ΠΌΠΈ, Π° Π½Π΅ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΈΠΌ ΠΈ Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΌ. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ ΠΎΠ±Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠ° Ρ„ΠΈΠ³ΡƒΡ€ ΠΈΠΌΠ΅ΡŽΡ‚ Ρ€Π°Π·Π½Ρ‹Π΅ Π½Π°Π±ΠΎΡ€Ρ‹ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ², Ρ€Π°Π·Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ ΠΌΠΎΠ³ΡƒΡ‚ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ Π΅Ρ‰Π΅ большС Ρ€Π°Π·Π½Ρ‹Ρ… ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠΉ. ЕдинствСнноС, Ρ‡Ρ‚ΠΎ Ρƒ Π½ΠΈΡ… ΠΎΠ±Ρ‰Π΅Π³ΠΎ, это ΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡ‚ΡŒ Π²Ρ‹Ρ‡ΠΈΡΠ»ΡΡ‚ΡŒ ΠΈΡ… ΠΏΠ»ΠΎΡ‰Π°Π΄ΡŒ.

Π‘ этой Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏ Shape взаимозамСняСмо с Π΅Π³ΠΎ Square ΠΈ Rectangle ΠΏΠΎΠ΄Ρ‚ΠΈΠΏΠ°ΠΌΠΈ, ΠΊΠΎΠ³Π΄Π° вас интСрСсуСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΡ… ΠΎΠ±Ρ‰Π΅Π΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅:

>>> from shapes_lsp import Rectangle, Square

>>> def get_total_area(shapes):
...     return sum(shape.calculate_area() for shape in shapes)

>>> get_total_area([Rectangle(10, 5), Square(5)])
75

Π—Π΄Π΅ΡΡŒ Π²Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚Π΅ ΠΏΠ°Ρ€Ρƒ, ΡΠΎΡΡ‚ΠΎΡΡ‰ΡƒΡŽ ΠΈΠ· ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠ° ΠΈ ΠΊΠ²Π°Π΄Ρ€Π°Ρ‚Π°, Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая вычисляСт ΠΈΡ… ΠΎΠ±Ρ‰ΡƒΡŽ ΠΏΠ»ΠΎΡ‰Π°Π΄ΡŒ. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ функция заботится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ .calculate_area(), Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ значСния, Ρ‡Ρ‚ΠΎ Ρ„ΠΎΡ€ΠΌΡ‹ Ρ€Π°Π·Π½Ρ‹Π΅. Π’ этом ΡΡƒΡ‚ΡŒ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° подстановки Лисков.

🧱 SOLID-ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹: Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ΠΈ Π·Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½Ρ‹. Π Π°Π·Π±ΠΈΡ€Π°Π΅ΠΌ ΠΏΠΎ Π±ΡƒΠΊΠ²Π°ΠΌ

4. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ раздСлСния интСрфСйсов (ISP)

ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ раздСлСния интСрфСйсов (ISP) исходит ΠΈΠ· Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ°, Ρ‡Ρ‚ΠΎ ΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ СдинствСнной отвСтствСнности. Π”Π°, это Π΅Ρ‰Π΅ ΠΎΠ΄Π½ΠΎ ΠΏΠ΅Ρ€ΠΎ Π² шляпС дяди Π‘ΠΎΠ±Π°. Основная идСя ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ:

ΠšΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ² Π½Π΅ слСдуСт Π·Π°ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ½ΠΈ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚. Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡΡ‹ ΠΏΡ€ΠΈΠ½Π°Π΄Π»Π΅ΠΆΠ°Ρ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°ΠΌ, Π° Π½Π΅ иСрархиям.

Π’ этом случаС ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρ‹ β€” это классы ΠΈ подклассы, Π° интСрфСйсы состоят ΠΈΠ· ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΈ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ². Π”Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, Ссли класс Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈΠ»ΠΈ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹, Ρ‚ΠΎ эти ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ Π½Π° Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ классы.

Рассмотрим ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠΈ классов для модСлирования ΠΏΠ΅Ρ‡Π°Ρ‚Π½Ρ‹Ρ… машин:

# printers_isp.py

from abc import ABC, abstractmethod

class Printer(ABC):
    @abstractmethod
    def print(self, document):
        pass

    @abstractmethod
    def fax(self, document):
        pass

    @abstractmethod
    def scan(self, document):
        pass

class OldPrinter(Printer):
    def print(self, document):
        print(f"Printing {document} in black and white...")

    def fax(self, document):
        raise NotImplementedError("Fax functionality not supported")

    def scan(self, document):
        raise NotImplementedError("Scan functionality not supported")

class ModernPrinter(Printer):
    def print(self, document):
        print(f"Printing {document} in color...")

    def fax(self, document):
        print(f"Faxing {document}...")

    def scan(self, document):
        print(f"Scanning {document}...")

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ класс Printer прСдоставляСт интСрфСйс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ подклассы. OldPrinter наслСдуСтся ΠΎΡ‚ Printer ΠΈ Π΄ΠΎΠ»ΠΆΠ΅Π½ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚ΠΎΡ‚ ΠΆΠ΅ интСрфСйс. Однако OldPrinter Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ .fax() ΠΈ .scan(), ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ этот Ρ‚ΠΈΠΏ ΠΏΡ€ΠΈΠ½Ρ‚Π΅Ρ€Π° Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ эти Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.

Π­Ρ‚Π° рСализация Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ ISP, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ½Π° Π²Ρ‹Π½ΡƒΠΆΠ΄Π°Π΅Ρ‚ OldPrinter ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ интСрфСйс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ класс Π½Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅Ρ‚ ΠΈΠ»ΠΈ Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚. Π§Ρ‚ΠΎΠ±Ρ‹ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ интСрфСйсы Π½Π° Π±ΠΎΠ»Π΅Π΅ ΠΌΠ΅Π»ΠΊΠΈΠ΅ ΠΈ Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ классы. Π—Π°Ρ‚Π΅ΠΌ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ классы, наслСдуя нСсколько классов интСрфСйса ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ нСобходимости:

# printers_isp.py

from abc import ABC, abstractmethod

class Printer(ABC):
    @abstractmethod
    def print(self, document):
        pass

class Fax(ABC):
    @abstractmethod
    def fax(self, document):
        pass

class Scanner(ABC):
    @abstractmethod
    def scan(self, document):
        pass

class OldPrinter(Printer):
    def print(self, document):
        print(f"Printing {document} in black and white...")

class NewPrinter(Printer, Fax, Scanner):
    def print(self, document):
        print(f"Printing {document} in color...")

    def fax(self, document):
        print(f"Faxing {document}...")

    def scan(self, document):
        print(f"Scanning {document}...")

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Printer, Fax ΠΈ Scanner ΡΠ²Π»ΡΡŽΡ‚ΡΡ Π±Π°Π·ΠΎΠ²Ρ‹ΠΌΠΈ классами, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ интСрфСйсы с ΠΎΠ΄Π½ΠΎΠΉ ΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²Π΅Π½Π½ΠΎΡΡ‚ΡŒΡŽ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ. Π§Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ OldPrinter, Π²Ρ‹ наслСдуСтС Ρ‚ΠΎΠ»ΡŒΠΊΠΎ интСрфСйс Printer. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π² классС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ². Π§Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ класс ModernPrinter, Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΎΡ‚ всСх интСрфСйсов. ΠšΠΎΡ€ΠΎΡ‡Π΅ говоря, Π²Ρ‹ Ρ€Π°Π·Π΄Π΅Π»ΠΈΠ»ΠΈ интСрфСйс Printer.

Π­Ρ‚ΠΎΡ‚ Π΄ΠΈΠ·Π°ΠΉΠ½ класса позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Ρ€Π°Π·Π½Ρ‹Π΅ ΠΌΠ°ΡˆΠΈΠ½Ρ‹ с Ρ€Π°Π·Π½Ρ‹ΠΌΠΈ Π½Π°Π±ΠΎΡ€Π°ΠΌΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, дСлая ваш Π΄ΠΈΠ·Π°ΠΉΠ½ Π±ΠΎΠ»Π΅Π΅ Π³ΠΈΠ±ΠΊΠΈΠΌ ΠΈ Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅ΠΌΡ‹ΠΌ.

5. ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ инвСрсии зависимостСй (DIP)

ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏ инвСрсии зависимостСй (DIP) являСтся послСдним ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠΌ Π² Π½Π°Π±ΠΎΡ€Π΅ SOLID. Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ гласит, Ρ‡Ρ‚ΠΎ: абстракции Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚ Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ. Π”Π΅Ρ‚Π°Π»ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚ абстракций.

Π­Ρ‚ΠΎ Π·Π²ΡƒΡ‡ΠΈΡ‚ довольно слоТно. Π’ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΡΡΠ½ΠΈΡ‚ΡŒ это. ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Π²Ρ‹ создаСтС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Ρƒ вас Π΅ΡΡ‚ΡŒ класс FrontEnd для ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ отобраТСния Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ. Π’ настоящСС врСмя ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, поэтому Π² ΠΈΡ‚ΠΎΠ³Π΅ Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄:

# app_dip.py

class FrontEnd:
    def __init__(self, back_end):
        self.back_end = back_end

    def display_data(self):
        data = self.back_end.get_data_from_database()
        print("Display data:", data)

class BackEnd:
    def get_data_from_database(self):
        return "Data from the database"

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ класс FrontEnd зависит ΠΎΡ‚ BackEnd класса ΠΈ Π΅Π³ΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ. МоТно ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ±Π° класса тСсно связаны. Π­Ρ‚Π° связь ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°ΠΌ с ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΡŒΡŽ. НапримСр, ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ быстро растСт, ΠΈ Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΎ ΠΌΠΎΠ³Π»ΠΎ ΡΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· REST API. Как Π±Ρ‹ Π’Ρ‹ это сдСлали?

Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ΄ΡƒΠΌΠ°Ρ‚ΡŒ ΠΎ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° BackEnd для получСния Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· REST API. Однако для этого Ρ‚Π°ΠΊΠΆΠ΅ потрСбуСтся ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ FrontEnd, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Π·Π°ΠΊΡ€Ρ‹Ρ‚ для ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΏΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡƒ открытости-закрытости.

Π§Ρ‚ΠΎΠ±Ρ‹ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ инвСрсии зависимостСй ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ваши классы зависимыми ΠΎΡ‚ абстракций, Π° Π½Π΅ ΠΎΡ‚ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΉ, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ BackEnd. Π’ этом ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ввСсти класс DataSource, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ прСдоставляСт интСрфСйс для использования Π² Π²Π°ΡˆΠΈΡ… ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… классах:

# app_dip.py

from abc import ABC, abstractmethod

class FrontEnd:
    def __init__(self, data_source):
        self.data_source = data_source

    def display_data(self):
        data = self.data_source.get_data()
        print("Display data:", data)

class DataSource(ABC):
    @abstractmethod
    def get_data(self):
        pass

class Database(DataSource):
    def get_data(self):
        return "Data from the database"

class API(DataSource):
    def get_data(self):
        return "Data from the API"

Π’ этом ΠΏΠ΅Ρ€Π΅ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Π²Π°ΡˆΠΈΡ… классов Π²Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ класс DataSource ΠΊΠ°ΠΊ Π°Π±ΡΡ‚Ρ€Π°ΠΊΡ†ΠΈΡŽ, которая прСдоставляСт Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΡ‹ΠΉ интСрфСйс ΠΈΠ»ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ .get_data(). ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΠΊΠ°ΠΊ FrontEnd Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ зависит ΠΎΡ‚ интСрфСйса, прСдоставляСмого DataSource, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ являСтся абстракциСй.

Π—Π°Ρ‚Π΅ΠΌ Π²Ρ‹ опрСдСляСтС Database класс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ являСтся ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ для Ρ‚Π΅Ρ… случаСв, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· своСй Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…. Π­Ρ‚ΠΎΡ‚ класс зависит ΠΎΡ‚ абстракции DataSource Ρ‡Π΅Ρ€Π΅Π· наслСдованиС. НаконСц, Π²Ρ‹ опрСдСляСтС API класс для ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ получСния Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· REST API. Π­Ρ‚ΠΎΡ‚ класс Ρ‚Π°ΠΊΠΆΠ΅ зависит ΠΎΡ‚ абстракции DataSource.

Π’ΠΎΡ‚ ΠΊΠ°ΠΊ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ FrontEnd класс Π² своСм ΠΊΠΎΠ΄Π΅:

>>> from app_dip import API, Database, FrontEnd

>>> db_front_end = FrontEnd(Database())
>>> db_front_end.display_data()
Display data: Data from the database

>>> api_front_end = FrontEnd(API())
>>> api_front_end.display_data()
Display data: Data from the API

Π—Π΄Π΅ΡΡŒ Π²Ρ‹ сначала ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ FrontEnd с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Database, Π° Π·Π°Ρ‚Π΅ΠΌ снова с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° API. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚Π΅ .display_data(), Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ источника Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ динамичСски ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ источник Π΄Π°Π½Π½Ρ‹Ρ…, ΠΏΠ΅Ρ€Π΅Π½Π°Π·Π½Π°Ρ‡ΠΈΠ² .data_source Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ Π² своСм FrontEnd экзСмплярС.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

Π’Ρ‹ ΠΌΠ½ΠΎΠ³ΠΎΠ΅ ΡƒΠ·Π½Π°Π»ΠΈ ΠΎ пяти ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ°Ρ… SOLID, Π² Ρ‚ΠΎΠΌ числС ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡ… Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚, ΠΈ ΠΊΠ°ΠΊ провСсти Ρ€Π΅Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΈΠ½Π³ ΠΊΠΎΠ΄Π° Π² соотвСтствии с Π»ΡƒΡ‡ΡˆΠΈΠΌΠΈ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°ΠΌΠΈ проСктирования. Π’Ρ‹ Π²ΠΈΠ΄Π΅Π»ΠΈ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠ΅ ΠΈ ΠΏΠ»ΠΎΡ…ΠΈΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹, связанныС с ΠΊΠ°ΠΆΠ΄Ρ‹ΠΌ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠΌ, ΠΈ ΡƒΠ·Π½Π°Π»ΠΈ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΠ² SOLID ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π²Π°ΠΌ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ ваш ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎ-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Π΄ΠΈΠ·Π°ΠΉΠ½ Π² Python.

Π’ этом ΡƒΡ€ΠΎΠΊΠ΅ Π²Ρ‹ ΡƒΠ·Π½Π°Π»ΠΈ, ΠΊΠ°ΠΊ:

  1. ΠŸΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ Ρ†Π΅Π»ΡŒ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° SOLID.
  2. Π’Ρ‹ΡΠ²Π»ΡΡ‚ΡŒ классы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π°Ρ€ΡƒΡˆΠ°ΡŽΡ‚ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID Π² Python.
  3. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ SOLID, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π²Π°ΠΌ Ρ€Π΅ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ Python ΠΈ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ ООП.

Благодаря этим знаниям, Ρƒ вас Π΅ΡΡ‚ΡŒ прочная основа Ρ…ΠΎΡ€ΠΎΡˆΠΎ Π·Π°Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΠΎΠ²Π°Π²ΡˆΠΈΡ… сСбя Π»ΡƒΡ‡ΡˆΠΈΡ… ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΏΡ€ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ своих классов ΠΈ ΠΈΡ… взаимосвязСй Π² Python. ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΡ эти ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄, Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ Π² сопровоТдСнии, Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅ΠΌΡ‹ΠΉ, ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ ΠΈ тСстируСмый.

***

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

admin
11 дСкабря 2018

ООП Π½Π° Python: ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python допускаСт Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ»ΠΎΠ³ΠΈΠΈ, Π½ΠΎ Π² Π΅Π³ΠΎ основС...
admin
28 июня 2018

3 самых Π²Π°ΠΆΠ½Ρ‹Ρ… сфСры примСнСния Python: возмоТности языка

БущСствуСт мноТСство областСй примСнСния Python, Π½ΠΎ Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠ½ особСнно...
admin
13 фСвраля 2017

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python: ΠΎΡ‚ Π½ΠΎΠ²ΠΈΡ‡ΠΊΠ° Π΄ΠΎ профСссионала

Пошаговая инструкция для всСх, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒΒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python...