Repository navigation
Expand file tree
/
Copy pathtemplate_method.py
More file actions
88 lines (64 loc) · 2.37 KB
/
Copy pathtemplate_method.py
File metadata and controls
88 lines (64 loc) · 2.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""
Template Method — the superclass orchestrates, subclasses fill the blanks
`Report.render()` is the skeleton: build header, body, footer, join.
Subclasses (`MarkdownReport`, `HTMLReport`, `PlainReport`) override
only the formatting hooks. The caller asks for `.render()` and never
has to know which flavour answered.
Compare with the procedural Python version:
def render(kind, title, rows):
match kind:
case "markdown":
return f"# {title}\n" + "\n".join(f"- {r}" for r in rows)
case "html":
return f"<h1>{title}</h1>\n<ul>...</ul>"
case "plain":
return title.upper() + "\n" + "\n".join(rows)
POOP forbids `match` and `for`-comprehensions. The shape lives in the
abstract class; each concrete report supplies its own pieces. The
caller dispatches on the receiver, not on a tag.
Smalltalk:
Object subclass: #Report
instanceVariableNames: 'title rows'.
Report>>render
^String streamContents: [:s |
s nextPutAll: self header; cr.
s nextPutAll: self body; cr.
s nextPutAll: self footer]
Report subclass: #MarkdownReport.
MarkdownReport>>header ^'# ', title
MarkdownReport>>body ^...
"""
class Report:
def __init__(self, title, rows):
self._title = title
self._rows = rows
def render(self):
return "\n".join([self.header(), self.body(), self.footer()])
class MarkdownReport(Report):
def header(self):
return "# " + self._title
def body(self):
return "\n".join(self._rows.map(lambda r: "- " + r))
def footer(self):
return "_rendered by POOP_"
class HTMLReport(Report):
def header(self):
return "<h1>" + self._title + "</h1>"
def body(self):
items = "\n".join(self._rows.map(lambda r: " <li>" + r + "</li>"))
return "<ul>\n" + items + "\n</ul>"
def footer(self):
return "<p>rendered by POOP</p>"
class PlainReport(Report):
def header(self):
return self._title.upper()
def body(self):
return "\n".join(self._rows.map(lambda r: " * " + r))
def footer(self):
return "--"
rows = ["apples", "oranges", "bananas"]
[
MarkdownReport("Shopping list", rows),
HTMLReport("Shopping list", rows),
PlainReport("Shopping list", rows),
].do(lambda report: (report.render() + "\n").print())