Skip to content

Commit 0b26d80

Browse files
committed
update Common Design Patterns
1 parent eb70852 commit 0b26d80

File tree

2 files changed

+58
-187
lines changed

2 files changed

+58
-187
lines changed

notebooks/CommonDesignPatterns.ipynb

Lines changed: 22 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"- topics:\n",
1212
" - the Singleton pattern\n",
1313
" - the Decorator pattern\n",
14+
" - the Iterator pattern\n",
1415
" - the Observer pattern\n",
1516
" - the Strategy pattern\n",
1617
" - the Command pattern\n",
@@ -227,7 +228,7 @@
227228
},
228229
{
229230
"cell_type": "code",
230-
"execution_count": null,
231+
"execution_count": 1,
231232
"id": "0f8a6536",
232233
"metadata": {},
233234
"outputs": [],
@@ -237,7 +238,7 @@
237238
"from typing import List\n",
238239
"\n",
239240
"\n",
240-
"class Context():\n",
241+
"class Context:\n",
241242
" \"\"\"\n",
242243
" The Context defines the interface of interest to clients.\n",
243244
" \"\"\"\n",
@@ -316,10 +317,24 @@
316317
},
317318
{
318319
"cell_type": "code",
319-
"execution_count": null,
320+
"execution_count": 2,
320321
"id": "51e94a76",
321322
"metadata": {},
322-
"outputs": [],
323+
"outputs": [
324+
{
325+
"name": "stdout",
326+
"output_type": "stream",
327+
"text": [
328+
"Client: Strategy is set to normal sorting.\n",
329+
"Context: Sorting data using the strategy (not sure how it'll do it)\n",
330+
"a,b,c,d,e\n",
331+
"\n",
332+
"Client: Strategy is set to reverse sorting.\n",
333+
"Context: Sorting data using the strategy (not sure how it'll do it)\n",
334+
"e,d,c,b,a\n"
335+
]
336+
}
337+
],
323338
"source": [
324339
"context = Context(ConcreteStrategyA())\n",
325340
"print(\"Client: Strategy is set to normal sorting.\")\n",
@@ -538,7 +553,7 @@
538553
},
539554
{
540555
"cell_type": "code",
541-
"execution_count": 26,
556+
"execution_count": null,
542557
"id": "c7e13bcd",
543558
"metadata": {},
544559
"outputs": [],
@@ -612,8 +627,6 @@
612627
"Concrete States implement various behaviors, associated with a state of the\n",
613628
"Context.\n",
614629
"\"\"\"\n",
615-
"\n",
616-
"\n",
617630
"class ConcreteStateA(State):\n",
618631
" def handle1(self) -> None:\n",
619632
" print(\"ConcreteStateA handles request1.\")\n",
@@ -939,182 +952,6 @@
939952
"result"
940953
]
941954
},
942-
{
943-
"cell_type": "markdown",
944-
"id": "88c5fa34",
945-
"metadata": {},
946-
"source": [
947-
"## The Single pattern\n",
948-
"\n",
949-
"- also called anti-pattern \n",
950-
"- more common in more strict OOP languages such as Java than in scripting languages such as Python\n",
951-
"- the basic idea is to allow exactly one instance of certain objects in the program\n",
952-
"\n",
953-
"![Single pattern](resources/singleton_pattern.png)\n",
954-
"\n",
955-
"- singletons are normally enforced by making the constructor private (so no one can create additional instances of it)\n",
956-
"- then providing a static method to retrieve the single instance. \n",
957-
" - this method creates a new instance the first time it is called and then returns that same instance for all subsequent calls\n",
958-
" \n",
959-
"- since python doesn't have a private access specifier, we've to be a little creative\n",
960-
"- can use `__new__()` method and class variable to ensure that only one instance is created"
961-
]
962-
},
963-
{
964-
"cell_type": "code",
965-
"execution_count": 38,
966-
"id": "57c525e2",
967-
"metadata": {},
968-
"outputs": [],
969-
"source": [
970-
"class OneOnly:\n",
971-
" _singleton = None\n",
972-
" # not the use of cls instead of self to clarify the usage of _sigleton class variable\n",
973-
" def __new__(cls, *args, **kwargs):\n",
974-
" if not cls._singleton:\n",
975-
" cls._singleton = super().__new__(cls, *args, **kwargs)\n",
976-
" return cls._singleton\n",
977-
" \n",
978-
" def business_operation(self):\n",
979-
" print('perform some business opearation')"
980-
]
981-
},
982-
{
983-
"cell_type": "code",
984-
"execution_count": 35,
985-
"id": "8b4c8be8",
986-
"metadata": {},
987-
"outputs": [],
988-
"source": [
989-
"s1 = OneOnly()\n",
990-
"s2 = OneOnly()"
991-
]
992-
},
993-
{
994-
"cell_type": "code",
995-
"execution_count": 36,
996-
"id": "151266d1",
997-
"metadata": {},
998-
"outputs": [
999-
{
1000-
"data": {
1001-
"text/plain": [
1002-
"True"
1003-
]
1004-
},
1005-
"execution_count": 36,
1006-
"metadata": {},
1007-
"output_type": "execute_result"
1008-
}
1009-
],
1010-
"source": [
1011-
"s1 == s2"
1012-
]
1013-
},
1014-
{
1015-
"cell_type": "code",
1016-
"execution_count": 37,
1017-
"id": "fce54ad5",
1018-
"metadata": {},
1019-
"outputs": [
1020-
{
1021-
"data": {
1022-
"text/plain": [
1023-
"True"
1024-
]
1025-
},
1026-
"execution_count": 37,
1027-
"metadata": {},
1028-
"output_type": "execute_result"
1029-
}
1030-
],
1031-
"source": [
1032-
"id(s1) == id(s2)"
1033-
]
1034-
},
1035-
{
1036-
"cell_type": "code",
1037-
"execution_count": 5,
1038-
"id": "9a1107c4",
1039-
"metadata": {},
1040-
"outputs": [
1041-
{
1042-
"name": "stdout",
1043-
"output_type": "stream",
1044-
"text": [
1045-
"perform some business opearation\n"
1046-
]
1047-
}
1048-
],
1049-
"source": [
1050-
"s1.business_operation()"
1051-
]
1052-
},
1053-
{
1054-
"cell_type": "code",
1055-
"execution_count": 6,
1056-
"id": "a3eacfbb",
1057-
"metadata": {},
1058-
"outputs": [
1059-
{
1060-
"data": {
1061-
"text/plain": [
1062-
"<__main__.OneOnly at 0x7f9ce6a4f3d0>"
1063-
]
1064-
},
1065-
"execution_count": 6,
1066-
"metadata": {},
1067-
"output_type": "execute_result"
1068-
}
1069-
],
1070-
"source": [
1071-
"s1"
1072-
]
1073-
},
1074-
{
1075-
"cell_type": "code",
1076-
"execution_count": 7,
1077-
"id": "611a4d3f",
1078-
"metadata": {},
1079-
"outputs": [
1080-
{
1081-
"data": {
1082-
"text/plain": [
1083-
"<__main__.OneOnly at 0x7f9ce6a4f3d0>"
1084-
]
1085-
},
1086-
"execution_count": 7,
1087-
"metadata": {},
1088-
"output_type": "execute_result"
1089-
}
1090-
],
1091-
"source": [
1092-
"s2"
1093-
]
1094-
},
1095-
{
1096-
"cell_type": "markdown",
1097-
"id": "395e9fc5",
1098-
"metadata": {},
1099-
"source": [
1100-
"### Python singleton\n",
1101-
"\n",
1102-
"- Python provides two built-in Singleton patterns we can leverage\n",
1103-
"- rather than invent something hard to read, there are two choices:\n",
1104-
"\n",
1105-
"1. Python *module*:\n",
1106-
" - One `import` will create a module\n",
1107-
" - all other attempts to import the module return the one-and-only singleton instance of the module\n",
1108-
"\n",
1109-
"2. Python *class* definition:\n",
1110-
" - a Python class can only be created once in a given namespace\n",
1111-
" - consider using a class with class-level attributes as a singleton object\n",
1112-
" - use `@staticmethod` decorator to not have to use instance variable `self`\n",
1113-
" \n",
1114-
"- see https://github.com/rambasnet/Kattis-Demos-Testing/blob/main/hello/python3/OOP/main.py solution that uses single object of Main class to solve the problem\n",
1115-
"- see https://github.com/rambasnet/Kattis-Demos-Testing/tree/main/egypt/python3/OOP/main_singleton.py solution that uses static methods and class level variables to use a single pattern"
1116-
]
1117-
},
1118955
{
1119956
"cell_type": "markdown",
1120957
"id": "e12acc78",
@@ -1142,7 +979,7 @@
1142979
],
1143980
"metadata": {
1144981
"kernelspec": {
1145-
"display_name": "Python 3 (ipykernel)",
982+
"display_name": "oop",
1146983
"language": "python",
1147984
"name": "python3"
1148985
},
@@ -1156,7 +993,7 @@
1156993
"name": "python",
1157994
"nbconvert_exporter": "python",
1158995
"pygments_lexer": "ipython3",
1159-
"version": "3.10.8"
996+
"version": "3.10.9"
1160997
}
1161998
},
1162999
"nbformat": 4,

notebooks/PythonObjects-Singleton.ipynb

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,8 +994,20 @@
994994
"id": "1f17389d",
995995
"metadata": {},
996996
"source": [
997-
"## Singleton Pattern\n",
997+
"## The Singleton Pattern\n",
998998
"\n",
999+
"- also called anti-pattern \n",
1000+
"- more common in more strict OOP languages such as Java than in scripting languages such as Python\n",
1001+
"- the basic idea is to allow exactly one instance of certain objects in the program\n",
1002+
"\n",
1003+
"![Single pattern](resources/singleton_pattern.png)\n",
1004+
"\n",
1005+
"- singletons are normally enforced by making the constructor private (so no one can create additional instances of it)\n",
1006+
"- then providing a static method to retrieve the single instance. \n",
1007+
" - this method creates a new instance the first time it is called and then returns that same instance for all subsequent calls\n",
1008+
" \n",
1009+
"- since python doesn't have a private access specifier, we've to be a little creative\n",
1010+
"- can use `__new__()` method and class variable to ensure that only one instance is created\n",
9991011
"- also called anti-pattern because there is only one instance of the class\n",
10001012
"- use `__new__()` method to create a new instance of the class\n",
10011013
"- `__new__()` is a class method that is called before the `__init__()` instance method\n",
@@ -1023,7 +1035,7 @@
10231035
" # we don't care about (a, b) so use args and kwargs within __new__\n",
10241036
" # not providing them will create syntax error because __init__ is defined with two arguments \n",
10251037
" if not cls._instance:\n",
1026-
" cls._instance = super().__new__(cls)\n",
1038+
" cls._instance = super().__new__(cls, *args, **kwargs)\n",
10271039
" return cls._instance\n",
10281040
"\n",
10291041
" def __init__(self, a, b):\n",
@@ -1133,6 +1145,28 @@
11331145
"test_singleton()"
11341146
]
11351147
},
1148+
{
1149+
"cell_type": "markdown",
1150+
"id": "0ffd34ad",
1151+
"metadata": {},
1152+
"source": [
1153+
"### Python singleton\n",
1154+
"\n",
1155+
"- Python provides two built-in Singleton patterns we can leverage\n",
1156+
"- rather than invent something hard to read, there are two choices:\n",
1157+
"\n",
1158+
"1. Python *module*:\n",
1159+
" - One `import` will create a module\n",
1160+
" - all other attempts to import the module return the one-and-only singleton instance of the module\n",
1161+
"\n",
1162+
"2. Python *class* definition:\n",
1163+
" - a Python class can only be created once in a given namespace\n",
1164+
" - consider using a class with class-level attributes as a singleton object\n",
1165+
" - use `@staticmethod` decorator to not have to use instance variable `self`\n",
1166+
" \n",
1167+
"- see `demo-assignments/A1-OOP` and `demo-assignments/A2-ABC` for single pattern examples"
1168+
]
1169+
},
11361170
{
11371171
"cell_type": "markdown",
11381172
"id": "ce4e86ec",

0 commit comments

Comments
 (0)