Utoljára aktív 10 months ago

Python Mixin 設計模式允許類別透過多重繼承增加功能,如日誌、權限管理、事件驅動、異常處理與審計,提升可維護性與擴展性,適用於模組化應用開發。

user_with_logging_and_permissions.py Eredeti
1import datetime
2import json
3import threading
4import traceback
5
6class LoggingMixin:
7 def __init__(self, log_to_file=False, log_file="app.log", *args, **kwargs):
8 self.log_to_file = log_to_file
9 self.log_file = log_file
10 super().__init__(*args, **kwargs)
11
12 def log(self, message):
13 timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
14 log_message = f"[{timestamp}] {self.__class__.__name__}: {message}"
15 if self.log_to_file:
16 with open(self.log_file, "a") as f:
17 f.write(log_message + "\n")
18 else:
19 print(log_message)
20
21class TimestampMixin:
22 def __init__(self, *args, **kwargs):
23 self.created_at = datetime.datetime.now().isoformat()
24 self.updated_at = self.created_at
25 super().__init__(*args, **kwargs)
26
27 def update_timestamp(self):
28 self.updated_at = datetime.datetime.now().isoformat()
29 self.log(f"更新時間標記: {self.updated_at}")
30
31class DatabaseMixin:
32 _database = {}
33
34 def save(self):
35 DatabaseMixin._database[self.name] = json.dumps(self.__dict__, default=str)
36 self.log(f"資料已儲存: {self.name}")
37
38 @classmethod
39 def get(cls, name):
40 data = cls._database.get(name, None)
41 return json.loads(data) if data else None
42
43class PermissionMixin:
44 _roles_permissions = {
45 "admin": ["create", "read", "update", "delete"],
46 "editor": ["create", "read", "update"],
47 "viewer": ["read"]
48 }
49
50 def __init__(self, role="viewer", *args, **kwargs):
51 self.role = role
52 self.permissions = self._roles_permissions.get(role, [])
53 super().__init__(*args, **kwargs)
54
55 def has_permission(self, perm):
56 return perm in self.permissions
57
58 def change_role(self, new_role):
59 self.role = new_role
60 self.permissions = self._roles_permissions.get(new_role, [])
61 self.log(f"角色變更為 {new_role},新權限: {self.permissions}")
62
63class EventMixin:
64 _events = {}
65
66 @classmethod
67 def on(cls, event_name, callback, async_mode=False):
68 if event_name not in cls._events:
69 cls._events[event_name] = []
70 cls._events[event_name].append((callback, async_mode))
71
72 @classmethod
73 def trigger(cls, event_name, *args, **kwargs):
74 if event_name in cls._events:
75 for callback, async_mode in cls._events[event_name]:
76 if async_mode:
77 threading.Thread(target=callback, args=args, kwargs=kwargs).start()
78 else:
79 callback(*args, **kwargs)
80
81class ExceptionHandlingMixin:
82 def handle_exception(self, func, *args, **kwargs):
83 try:
84 return func(*args, **kwargs)
85 except Exception as e:
86 self.log(f"發生異常: {e}")
87 traceback.print_exc()
88
89class AuditMixin:
90 _audit_log = []
91
92 def audit(self, action, details):
93 record = {
94 "timestamp": datetime.datetime.now().isoformat(),
95 "user": self.name,
96 "action": action,
97 "details": details
98 }
99 self._audit_log.append(record)
100 self.log(f"審計記錄: {record}")
101
102class User(LoggingMixin, TimestampMixin, DatabaseMixin, PermissionMixin, EventMixin, ExceptionHandlingMixin, AuditMixin):
103 def __init__(self, name, role="viewer", log_to_file=False):
104 super().__init__(role=role, log_to_file=log_to_file)
105 self.name = name
106 self.log(f"User '{self.name}' 已建立,角色: {self.role}")
107
108 def update_name(self, new_name):
109 self.audit("update_name", {"old_name": self.name, "new_name": new_name})
110 self.log(f"名稱從 '{self.name}' 變更為 '{new_name}'")
111 old_name = self.name
112 self.name = new_name
113 self.update_timestamp()
114 self.trigger("user_updated", old_name, new_name)
115
116# 測試範例
117if __name__ == "__main__":
118 # 訂閱事件
119 def on_user_updated(old_name, new_name):
120 print(f"🔔 使用者名稱變更通知: {old_name}{new_name}")
121
122 User.on("user_updated", on_user_updated)
123 User.on("user_updated", lambda o, n: print(f"📡 非同步通知: {o}{n}"), async_mode=True)
124
125 # 建立使用者
126 user1 = User("Alice", role="editor", log_to_file=True)
127 user1.save()
128
129 # 更新名稱
130 user1.update_name("Alice_Wonderland")
131
132 # 檢查權限
133 print(f"Alice 是否有 'read' 權限?{user1.has_permission('read')}")
134 print(f"Alice 是否有 'delete' 權限?{user1.has_permission('delete')}")
135
136 # 變更角色
137 user1.change_role("admin")
138
139 # 從資料庫取得使用者
140 retrieved_user = User.get("Alice_Wonderland")
141 if retrieved_user:
142 print(f"從資料庫取得使用者: {retrieved_user}")
143
144 # 測試異常處理
145 user1.handle_exception(lambda: 1 / 0)
146