Частина 3/3: Основи архітектури програмного забезпечення та шаблонів проектування

pic

Вступ 3

Остання частина серії про шаблони проектування зосереджена на прикладах та практичних реалізаціях. Ми заглибимося в різні типи та принципи шаблонів проектування та розглянемо, як їх можна застосовувати у ваших проєктах.

Шаблони проектування в розробці програмного забезпечення

1. Створювальні шаблони (механізми створення об'єктів)

  • Singleton (Одиничний об'єкт): Забезпечує створення лише одного екземпляра класу та надає глобальну точку доступу до нього.
  • Factory Method (Фабричний метод): Створює об'єкти без вказівки точного класу для створення.
  • Abstract Factory (Абстрактна фабрика): Надає інтерфейс для створення сімейств пов'язаних або залежних об'єктів без вказівки їх конкретних класів.
  • Builder (Будівельник): Розділяє побудову складного об'єкта від його представлення.
  • Prototype (Прототип): Створює нові об'єкти шляхом копіювання існуючого об'єкта, відомого як прототип.

2. Структурні шаблони (складання класів чи об'єктів)

  • Adapter (Адаптер): Дозволяє несумісним інтерфейсам працювати разом.
  • Bridge (Міст): Розділяє абстракцію об'єкта від його реалізації.
  • Composite (Композиція): Складує об'єкти в деревоподібні структури для представлення ієрархій частина-ціле.
  • Decorator (Декоратор): Додає нову функціональність об'єкту динамічно.
  • Facade (Фасад): Надає спрощений інтерфейс до складної системи.
  • Flyweight (Летючий вагон): Зменшує використання пам'яті, спільно використовуючи спільні частини стану між кількома об'єктами.
  • Proxy (Проксі): Надає заступника для іншого об'єкта для контролю доступу до нього.

3. Поведінкові шаблони (комунікація між об'єктами)

  • Chain of Responsibility (Цепочка відповідальностей): Пересилає запити вздовж ланцюга обробників.
  • Command (Команда): Інкапсулює запит як об'єкт, дозволяючи параметризувати запити.
  • Interpreter (Інтерпретатор): Визначає граматику для інтерпретації речень у мові.
  • Iterator (Ітератор): Надає спосіб доступу до елементів колекції послідовно.
  • Mediator (Посередник): Зменшує зв'язність між класами, централізуючи комунікацію.
  • Memento (Мементо): Захоплює та відновлює внутрішній стан об'єкта.
  • Observer (Спостерігач): Визначає залежність між об'єктами так, щоб коли один змінює стан, всі залежні отримують сповіщення.
  • State (Стан): Дозволяє об'єкту змінювати свою поведінку при зміні внутрішнього стану.
  • Strategy (Стратегія): Визначає родину алгоритмів, інкапсулює кожен з них і робить їх взаємозамінними.
  • Template Method (Шаблонний метод): Визначає каркас алгоритму, відсуваючи кроки на підкласи.
  • Visitor (Візитер): Додає нові операції до ієрархії класів без модифікації самих класів.

4. Шаблони для багатозадачності (управління багатопотоковими додатками)

  • Active Object (Активний об'єкт): Відокремлює виконання методу від виклику методу.
  • Balking (Пропуск): Перешкоджає виконанню операції, якщо об'єкт знаходиться в неправильному стані.
  • Double-Checked Locking (Подвійна перевірка блокування): Зменшує накладні витрати при ініціалізації ресурсів у багатопотоковому середовищі.
  • Guarded Suspension (Охоронюване призупинення): Керує операціями, які потребують виконання попередніх умов.
  • Monitor Object (Об'єкт монітору): Синхронізує доступ до об'єкта між кількома потоками.
  • Read-Write Lock (Блокування на читання-запис): Дозволяє кільком читачам або одному записувачу працювати одночасно.
  • Thread Pool (Пул потоків): Керує пулом робочих потоків для ефективного оброблення кількох задач.

5.

Архітектурні шаблони (високорівневі структури програмних систем)

  • Шарова архітектура (n-tier): Організовує систему в шари з конкретними обов'язками.
  • Клієнт-сервер: Розділяє ролі клієнта та сервера.
  • Майстер-слуга: Розділяє розподілені процеси на майстрів та слуг.
  • Трубопровід і фільтр: Розбиває процеси на послідовність етапів обробки.
  • Модель-вид-контролер (MVC): Розділяє завдання на модель, вид та контролер.
  • Модель-вид-Модель перегляду (MVVM): Розділяє логіку та інтерфейс користувача, часто використовується в таких фреймворках, як WPF.
  • Мікросервісна архітектура: Організовує додаток як набір малих, незалежних сервісів.
  • Подієво-орієнтована архітектура: Використовує події для ініціювання комунікації між розслабленими сервісами.
  • Архітектура на основі простору: Зменшує навантаження на бази даних за допомогою збереження даних у пам'яті.
  • Архітектура орієнтована на сервіси (SOA): Створює системи з використанням повторно використовуваних сервісів.

6. Шаблони для хмарних та розподілених систем

  • Запобіжник ланцюга: Перешкоджає повторному виконанню невдалих запитів.
  • API Gateway: Діє як єдина точка входу для всіх мікросервісів.
  • Сервісна сітка: Керує комунікацією між сервісами.
  • Шаблон Сайдкар: Додає додаткову функціональність до сервісу без модифікації.
  • Шаблон Сага: Керує розподіленими транзакціями за допомогою компенсуючих транзакцій.
  • CQRS (Сегрегація команд та запитів): Розділяє команди від запитів.
  • Подієвий джерело: Зберігає зміни стану як послідовність подій.

7. Шаблони інтеграції підприємств

  • Агрегатор: Об'єднує кілька повідомлень в одне.
  • Повідомлювач: Направляє повідомлення між сервісами.
  • Черга повідомлень: Керує доставкою повідомлень між сервісами.
  • Маршрутизатор на основі вмісту: Направляє повідомлення на основі їх вмісту.
  • Канал Publish-Subscribe: Відправляє повідомлення кільком підписникам.

Тепер давайте заглибимося в практичні приклади цих шаблонів проектування на Python!

1.

Створювальні шаблони

Шаблон Singleton

Гарантує, що в класі існує лише один екземпляр, і надає глобальну точку доступу до цього екземпляра.

Приклад на Python:

class Singleton:  
 _instance = None  
def __new__(cls):  
 if cls._instance is None:  
 cls._instance = super().__new__(cls)  
 return cls._instance  
# Використання  
s1 = Singleton()  
s2 = Singleton()  
print(s1 is s2) # True

Шаблон Factory Method

Визначає інтерфейс для створення об'єктів, але дозволяє підкласам змінювати типи об'єктів, що будуть створені.

Приклад:

from abc import ABC, abstractmethod  
class Product(ABC):  
 @abstractmethod  
 def operation(self):  
 pass  
class ConcreteProductA(Product):  
 def operation(self):  
 return "Product A"  
class ConcreteProductB(Product):  
 def operation(self):  
 return "Product B"  
class Factory:  
 @staticmethod  
 def create_product(type_):  
 if type_ == "A":  
 return ConcreteProductA()  
 elif type_ == "B":  
 return ConcreteProductB()  
 raise ValueError("Unknown product type")  
# Використання  
product = Factory.create_product("A")  
print(product.operation()) # "Product A"

Шаблон Abstract Factory

Надає інтерфейс для створення родин пов'язаних або залежних об'єктів.

Приклад:

class AbstractFactory(ABC):  
 @abstractmethod  
 def create_product(self):  
 pass  
class ConcreteFactoryA(AbstractFactory):  
 def create_product(self):  
 return ConcreteProductA()  
class ConcreteFactoryB(AbstractFactory):  
 def create_product(self):  
 return ConcreteProductB()  
# Використання  
factory = ConcreteFactoryA()  
product = factory.create_product()  
print(product.operation()) # "Product A"

Шаблон Builder

Розділяє процес створення об'єкта від його представленості.

Приклад:

class Product:  
 def __init__(self):  
 self.parts = []  
def add(self, part):  
 self.parts.append(part)  
 def show(self):  
 print(", ".join(self.parts))  
class Builder:  
 def build_part(self):  
 pass  
class ConcreteBuilder(Builder):  
 def __init__(self):  
 self.product = Product()  
 def build_part(self):  
 self.product.add("Part A")  
 self.product.add("Part B")  
 def get_result(self):  
 return self.product  
# Використання  
builder = ConcreteBuilder()  
builder.build_part()  
product = builder.get_result()  
product.show() # "Part A, Part B"

Шаблон Prototype

Створює об'єкти шляхом клонування існуючого об'єкта.

Приклад:

import copy  
class Prototype:  
 def clone(self):  
 return copy.deepcopy(self)  
class ConcretePrototype(Prototype):  
 def __init__(self, value):  
 self.value = value  
# Використання  
prototype = ConcretePrototype([1, 2, 3])  
clone = prototype.clone()  
print(clone.value) # [1, 2, 3]

2.

Структурні шаблони

Шаблон Adapter

Дозволяє несумісним інтерфейсам працювати разом.

Приклад:

class OldSystem:  
 def specific_request(self):  
 return "Old system output"  
class Adapter:  
 def __init__(self, old_system):  
 self.old_system = old_system  
 def request(self):  
 return self.old_system.specific_request()  
# Використання  
adapter = Adapter(OldSystem())  
print(adapter.request()) # "Old system output"

Шаблон Bridge

Розділяє абстракцію від реалізації.

Приклад:

class Implementation:  
 def operation(self):  
 pass  
class ConcreteImplementationA(Implementation):  
 def operation(self):  
 return "ConcreteImplementationA"  
class Abstraction:  
 def __init__(self, implementation):  
 self.implementation = implementation  
 def operation(self):  
 return self.implementation.operation()  
# Використання  
implementation = ConcreteImplementationA()  
abstraction = Abstraction(implementation)  
print(abstraction.operation()) # "ConcreteImplementationA"

Шаблон Decorator

Динамічно додає поведінку об'єктам.

Приклад:

class Component:  
 def operation(self):  
 pass  
class ConcreteComponent(Component):  
 def operation(self):  
 return "ConcreteComponent"  
class Decorator(Component):  
 def __init__(self, component):  
 self.component = component  
 def operation(self):  
 return f"Decorator({self.component.operation()})"  
# Використання  
component = ConcreteComponent()  
decorated = Decorator(component)  
print(decorated.operation()) # "Decorator(ConcreteComponent)"

Шаблон Facade

Надає спрощений інтерфейс для складної підсистеми.

Приклад:

class SubsystemA:  
 def operation(self):  
 return "SubsystemA"  
class SubsystemB:  
 def operation(self):  
 return "SubsystemB"  
class Facade:  
 def __init__(self):  
 self.subsystemA = SubsystemA()  
 self.subsystemB = SubsystemB()  
 def operation(self):  
 return f"{self.subsystemA.operation()} + {self.subsystemB.operation()}"  
# Використання  
facade = Facade()  
print(facade.operation()) # "SubsystemA + SubsystemB"

Поведінкові шаблони

Шаблон Observer

Дозволяє об'єктам сповіщати інші про зміни стану.

Приклад:

class Subject:  
 def __init__(self):  
 self._observers = []  
def attach(self, observer):  
 self._observers.append(observer)  
 def notify(self, message):  
 for observer in self._observers:  
 observer.update(message)  
class Observer:  
 def update(self, message):  
 print(f"Observer received: {message}")  
# Використання  
subject = Subject()  
observer = Observer()  
subject.attach(observer)  
subject.notify("Hello, World!") # "Observer received: Hello, World!"

Шаблон Command

Інкапсулює запит як об'єкт.

Приклад:

class Command:  
 def execute(self):  
 pass  
class ConcreteCommand(Command):  
 def __init__(self, receiver):  
 self.receiver = receiver  
 def execute(self):  
 self.receiver.action()  
class Receiver:  
 def action(self):  
 print("Action executed")  
# Використання  
receiver = Receiver()  
command = ConcreteCommand(receiver)  
command.execute() # "Action executed"

Шаблон State

Дозволяє об'єкту змінювати свою поведінку, коли змінюється його внутрішній стан.

Приклад:

class State:  
 def handle(self):  
 pass  
class ConcreteStateA(State):  
 def handle(self):  
 return "State A"  
class ConcreteStateB(State):  
 def handle(self):  
 return "State B"  
class Context:  
 def __init__(self, state):  
 self.state = state  
 def request(self):  
 return self.state.handle()  
# Використання  
context = Context(ConcreteStateA())  
print(context.request()) # "State A"  
context.state = ConcreteStateB()  
print(context.request()) # "State B"

## Поведінкові шаблони (продовження)

# Шаблон Chain of Responsibility

Передає запити по ланцюгу обробників.

## Приклад:

class Handler:
def init(self, successor=None):
self.successor = successor
def handlerequest(self, request):
if self.successor:
self.successor.handle
request(request)
class ConcreteHandlerA(Handler):
def handlerequest(self, request):
if request == "A":
print("Handled by HandlerA")
else:
super().handle
request(request)
class ConcreteHandlerB(Handler):
def handlerequest(self, request):
if request == "B":
print("Handled by HandlerB")
else:
super().handle
request(request)

Використання

handlerchain = ConcreteHandlerA(ConcreteHandlerB())
handler
chain.handle_request("B") # "Handled by HandlerB"
```

Шаблон Mediator

Зменшує зв'язок між об'єктами, централізуючи комунікацію між ними.

ІНШУ ЧАСТИНУ МОЖНА ЗНАЙТИ ТУТ fzeba.com.

(Копіювання, вставка та виправлення 50 блоків коду в Medium - це занадто багато. Якщо вас цікавить ця тема та повний список шаблонів проектування, будь ласка, відвідайте мій особистий сайт для повної статті. ДЯКУЮ!)

Висновок

Тепер у вас є комплексний посібник з шаблонів архітектури програмного забезпечення, що включає:

  • Шаблони створення: Singleton, Factory, Builder, Prototype
  • Структурні шаблони: Adapter, Bridge, Composite, Decorator, Facade
  • Поведінкові шаблони: Observer, Command, Strategy, State, Visitor
  • Шаблони паралельності: Thread Pool, Read-Write Lock, Circuit Breaker
  • Шаблони для хмарних обчислень: API Gateway, Saga, CQRS, Event Sourcing
  • Шаблони інтеграції в підприємствах (EIP): Aggregator, Message Broker, Content-Based Router, Pub-Sub

Читайте цю статтю та інші на fzeba.com.

Перекладено з: Part 3/3 Basics of Software Architecture and Design Patterns