Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: high-level architectural modernization (7 patterns: Composi…
…te, Proxy, Template, Iterator, Bridge, Chaining)
  • Loading branch information
Jorgeotero1998 committed Apr 16, 2026
commit 845185a4ef123d11512fde1f403cfc92f98309c3
35 changes: 10 additions & 25 deletions patterns/behavioral/chaining_method.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
from __future__ import annotations

from typing import Self

class Person:
def __init__(self, name: str) -> None:
self.name = name
self.age: int = 0

def do_action(self, action: Action) -> Action:
print(self.name, action.name, end=" ")
return action


class Action:
def __init__(self, name: str) -> None:
def set_name(self, name: str) -> Self:
self.name = name

def amount(self, val: str) -> Action:
print(val, end=" ")
return self

def stop(self) -> None:
print("then stop")


def main():
"""
>>> move = Action('move')
>>> person = Person('Jack')
>>> person.do_action(move).amount('5m').stop()
Jack move 5m then stop
"""
def set_age(self, age: int) -> Self:
self.age = age
return self

def __str__(self) -> str:
return f"Name: {self.name}, Age: {self.age}"

if __name__ == "__main__":
import doctest

doctest.testmod()
person = Person("Jorge").set_age(28).set_name("Jorge Otero")
print(person)
65 changes: 26 additions & 39 deletions patterns/behavioral/iterator.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,34 @@
"""
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
Implementation of the iterator pattern with a generator
from __future__ import annotations
from typing import List, Iterator, Iterable, TypeVar, Generic

*TL;DR
Traverses a container and accesses the container's elements.
"""
T = TypeVar("T")

class AlphabeticalOrderIterator(Iterator[T], Generic[T]):
def __init__(self, collection: List[T]) -> None:
self._collection = collection
self._position = 0

def count_to(count: int):
"""Counts by word numbers, up to a maximum of five"""
numbers = ["one", "two", "three", "four", "five"]
yield from numbers[:count]
def __next__(self) -> T:
try:
value = self._collection[self._position]
self._position += 1
except IndexError:
raise StopIteration()
return value

class WordsCollection(Iterable[T], Generic[T]):
def __init__(self, collection: List[T] = []) -> None:
self._collection = collection

# Test the generator
def count_to_two() -> None:
return count_to(2)


def count_to_five() -> None:
return count_to(5)


def main():
"""
# Counting to two...
>>> for number in count_to_two():
... print(number)
one
two

# Counting to five...
>>> for number in count_to_five():
... print(number)
one
two
three
four
five
"""
def __iter__(self) -> AlphabeticalOrderIterator[T]:
return AlphabeticalOrderIterator(self._collection)

def add_item(self, item: T) -> None:
self._collection.append(item)

if __name__ == "__main__":
import doctest

doctest.testmod()
collection = WordsCollection[str]()
collection.add_item("First")
collection.add_item("Second")
collection.add_item("Third")
print("\n".join(collection))
85 changes: 20 additions & 65 deletions patterns/behavioral/template.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,28 @@
"""
An example of the Template pattern in Python
from __future__ import annotations
from abc import ABC, abstractmethod

*TL;DR
Defines the skeleton of a base algorithm, deferring definition of exact
steps to subclasses.
class AbstractClass(ABC):
def template_method(self) -> None:
self.base_operation1()
self.required_operations1()
self.base_operation2()
self.hook1()

*Examples in Python ecosystem:
Django class based views: https://docs.djangoproject.com/en/2.1/topics/class-based-views/
"""
def base_operation1(self) -> None:
print("AbstractClass: Doing the bulk of the work")

def base_operation2(self) -> None:
print("AbstractClass: Allowing subclasses to override operations")

def get_text() -> str:
return "plain-text"
@abstractmethod
def required_operations1(self) -> None: ...

def hook1(self) -> None: ...

def get_pdf() -> str:
return "pdf"


def get_csv() -> str:
return "csv"


def convert_to_text(data: str) -> str:
print("[CONVERT]")
return f"{data} as text"


def saver() -> None:
print("[SAVE]")


def template_function(getter, converter=False, to_save=False) -> None:
data = getter()
print(f"Got `{data}`")

if len(data) <= 3 and converter:
data = converter(data)
else:
print("Skip conversion")

if to_save:
saver()

print(f"`{data}` was processed")


def main():
"""
>>> template_function(get_text, to_save=True)
Got `plain-text`
Skip conversion
[SAVE]
`plain-text` was processed

>>> template_function(get_pdf, converter=convert_to_text)
Got `pdf`
[CONVERT]
`pdf as text` was processed

>>> template_function(get_csv, to_save=True)
Got `csv`
Skip conversion
[SAVE]
`csv` was processed
"""

class ConcreteClass(AbstractClass):
def required_operations1(self) -> None:
print("ConcreteClass: Implemented Operation1")

if __name__ == "__main__":
import doctest

doctest.testmod()
template = ConcreteClass()
template.template_method()
66 changes: 15 additions & 51 deletions patterns/structural/bridge.py
Original file line number Diff line number Diff line change
@@ -1,57 +1,21 @@
"""
*References:
http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Bridge_Pattern#Python
from __future__ import annotations
from typing import Protocol

*TL;DR
Decouples an abstraction from its implementation.
"""
from typing import Union
class Implementation(Protocol):
def operation_implementation(self) -> str: ...

class Abstraction:
def __init__(self, implementation: Implementation) -> None:
self.implementation = implementation

# ConcreteImplementor 1/2
class DrawingAPI1:
def draw_circle(self, x: int, y: int, radius: float) -> None:
print(f"API1.circle at {x}:{y} radius {radius}")


# ConcreteImplementor 2/2
class DrawingAPI2:
def draw_circle(self, x: int, y: int, radius: float) -> None:
print(f"API2.circle at {x}:{y} radius {radius}")


# Refined Abstraction
class CircleShape:
def __init__(
self, x: int, y: int, radius: int, drawing_api: Union[DrawingAPI2, DrawingAPI1]
) -> None:
self._x = x
self._y = y
self._radius = radius
self._drawing_api = drawing_api

# low-level i.e. Implementation specific
def draw(self) -> None:
self._drawing_api.draw_circle(self._x, self._y, self._radius)

# high-level i.e. Abstraction specific
def scale(self, pct: float) -> None:
self._radius *= pct


def main():
"""
>>> shapes = (CircleShape(1, 2, 3, DrawingAPI1()), CircleShape(5, 7, 11, DrawingAPI2()))

>>> for shape in shapes:
... shape.scale(2.5)
... shape.draw()
API1.circle at 1:2 radius 7.5
API2.circle at 5:7 radius 27.5
"""
def operation(self) -> str:
return f"Abstraction: Base operation with:\n{self.implementation.operation_implementation()}"

class ConcreteImplementationA:
def operation_implementation(self) -> str:
return "ConcreteImplementationA: Here's the result on the platform A."

if __name__ == "__main__":
import doctest

doctest.testmod()
implementation = ConcreteImplementationA()
abstraction = Abstraction(implementation)
print(abstraction.operation())
Loading