Skip to content

Commit d025459

Browse files
committed
Sample code for the SOLID principles article
1 parent 29ac594 commit d025459

File tree

6 files changed

+280
-0
lines changed

6 files changed

+280
-0
lines changed

solid-principles-python/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SOLID Principles: Improve Object-Oriented Design in Python
2+
3+
This folder provides the code examples for the article [SOLID Principles: Improve Object-Oriented Design in Python](https://realpython.com/solid-principles-python/).

solid-principles-python/app_dip.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from abc import ABC, abstractmethod
2+
3+
# Bad example
4+
# class Frontend:
5+
# """Frontend, concrete implementation."""
6+
7+
# def __init__(self, backend):
8+
# self.backend = backend
9+
10+
# def display_data(self):
11+
# data = self.backend.get_data_from_database()
12+
# print("Display data:", data)
13+
14+
15+
# class Backend:
16+
# """Backend, concrete implementation."""
17+
18+
# def get_data_from_database(self):
19+
# """Return data from the database."""
20+
# return "Data from the database"
21+
22+
23+
# Good example
24+
class Frontend:
25+
"""Frontend, concrete implementation."""
26+
27+
def __init__(self, data_source):
28+
self.data_source = data_source
29+
30+
def display_data(self):
31+
data = self.data_source.get_data()
32+
print("Display data:", data)
33+
34+
35+
class DataSource(ABC):
36+
"""DataSource interface (Abstraction)."""
37+
38+
@abstractmethod
39+
def get_data(self):
40+
pass
41+
42+
43+
class Database(DataSource):
44+
"""Database, concrete implementation."""
45+
46+
def get_data(self):
47+
"""Return data from the database."""
48+
return "Data from the database"
49+
50+
51+
class API(DataSource):
52+
"""API, concrete implementation."""
53+
54+
def get_data(self):
55+
"""Return data from the API."""
56+
return "Data from the API"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from pathlib import Path
2+
from zipfile import ZipFile
3+
4+
# Bad example
5+
# class FileManager:
6+
# def __init__(self, filename):
7+
# self.filename = Path(filename)
8+
9+
# def read(self):
10+
# with self.filename.open(mode="r") as file:
11+
# data = file.read()
12+
# return data
13+
14+
# def write(self, data):
15+
# with self.filename.open(mode="w") as file:
16+
# file.write(data)
17+
18+
# def compress(self):
19+
# with ZipFile(self.filename.stem + ".zip", mode="w") as archive:
20+
# archive.write(self.filename)
21+
22+
# def decompress(self, archive_name):
23+
# with ZipFile(archive_name, mode="r") as archive:
24+
# archive.extractall()
25+
26+
27+
# Good example
28+
class FileManager:
29+
def __init__(self, filename):
30+
self.filename = Path(filename)
31+
32+
def read(self):
33+
with self.filename.open(mode="r") as file:
34+
data = file.read()
35+
return data
36+
37+
def write(self, data):
38+
with self.filename.open(mode="w") as file:
39+
file.write(data)
40+
41+
42+
class ZipFileManager:
43+
def __init__(self, filename):
44+
self.filename = Path(filename)
45+
46+
def compress(self):
47+
with ZipFile(self.filename.stem + ".zip", mode="w") as archive:
48+
archive.write(self.filename)
49+
50+
def decompress(self, archive_name):
51+
with ZipFile(archive_name, mode="r") as archive:
52+
archive.extractall()
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from abc import ABC, abstractmethod
2+
3+
# Bad example
4+
# class Printer(ABC):
5+
# """Printer interface."""
6+
7+
# @abstractmethod
8+
# def print(self, document):
9+
# pass
10+
11+
# @abstractmethod
12+
# def fax(self, document):
13+
# pass
14+
15+
# @abstractmethod
16+
# def scan(self, document):
17+
# pass
18+
19+
20+
# class OldPrinter(Printer):
21+
# """Old printer, concrete implementation."""
22+
23+
# def print(self, document):
24+
# print(f"Print {document} in black and white")
25+
26+
# def fax(self, document):
27+
# raise NotImplementedError("Fax functionality not supported")
28+
29+
# def scan(self, document):
30+
# raise NotImplementedError("Scan functionality not supported")
31+
32+
33+
# class ModernPrinter(Printer):
34+
# """Modern printer, concrete implementation."""
35+
36+
# def print(self, document):
37+
# print(f"Printing {document} in color")
38+
39+
# def fax(self, document):
40+
# print(f"Faxing {document}")
41+
42+
# def scan(self, document):
43+
# print(f"Scanning {document}")
44+
45+
46+
# Good example
47+
class Printer(ABC):
48+
"""Printer interface."""
49+
50+
@abstractmethod
51+
def print(self, document):
52+
pass
53+
54+
55+
class Fax(ABC):
56+
"""Fax interface."""
57+
58+
@abstractmethod
59+
def fax(self, document):
60+
pass
61+
62+
63+
class Scan(ABC):
64+
"""Scan interface."""
65+
66+
@abstractmethod
67+
def scan(self, document):
68+
pass
69+
70+
71+
class OldPrinter(Printer):
72+
"""Old printer, concrete implementation."""
73+
74+
def print(self, document):
75+
print(f"Print {document} in black and white")
76+
77+
78+
class NewPrinter(Printer, Fax, Scan):
79+
"""New printer, concrete implementation."""
80+
81+
def print(self, document):
82+
print(f"Printing {document} in color")
83+
84+
def fax(self, document):
85+
print(f"Faxing {document}")
86+
87+
def scan(self, document):
88+
print(f"Scanning {document}")
89+
print(f"Scanning {document}")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class Rectangle:
2+
def __init__(self, width, height):
3+
self.width = width
4+
self.height = height
5+
6+
def area(self):
7+
return self.width * self.height
8+
9+
def perimeter(self):
10+
return 2 * (self.width + self.height)
11+
12+
13+
class Square(Rectangle):
14+
def __init__(self, side):
15+
super().__init__(side, side)
16+
self.side = side
17+
18+
@property
19+
def side(self):
20+
return self._side
21+
22+
@side.setter
23+
def side(self, value):
24+
self._side = value
25+
self.width = value
26+
self.height = value
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from abc import ABC, abstractmethod
2+
from math import pi
3+
4+
# class Shape:
5+
# def __init__(self, shape_type, **kwargs):
6+
# self.shape_type = shape_type
7+
# if self.shape_type == "rectangle":
8+
# self.width = kwargs["width"]
9+
# self.height = kwargs["height"]
10+
# elif self.shape_type == "circle":
11+
# self.radius = kwargs["radius"]
12+
13+
# def area(self):
14+
# if self.shape_type == "rectangle":
15+
# return self.width * self.height
16+
# elif self.shape_type == "circle":
17+
# return pi * self.radius**2
18+
19+
20+
class Shape(ABC):
21+
def __init__(self, shape_type):
22+
self.shape_type = shape_type
23+
24+
@abstractmethod
25+
def area(self):
26+
pass
27+
28+
29+
class Circle(Shape):
30+
def __init__(self, radius):
31+
super().__init__("circle")
32+
self.radius = radius
33+
34+
def area(self):
35+
return pi * self.radius**2
36+
37+
38+
class Rectangle(Shape):
39+
def __init__(self, width, height):
40+
super().__init__("rectangle")
41+
self.width = width
42+
self.height = height
43+
44+
def area(self):
45+
return self.width * self.height
46+
47+
48+
class Square(Shape):
49+
def __init__(self, side):
50+
super().__init__("square")
51+
self.side = side
52+
53+
def area(self):
54+
return self.side**2

0 commit comments

Comments
 (0)