|
|
@@ -0,0 +1,208 @@
|
|
|
+from abc import ABC, abstractmethod
|
|
|
+from typing import List, Protocol
|
|
|
+
|
|
|
+"""
|
|
|
+Lec 3: 设计原则 (Design Principles)
|
|
|
+这些代码示例展示了 SOLID 原则及其他核心设计原则在 Python 中的实现。
|
|
|
+"""
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 1. 单一职责原则 (Single Responsibility Principle, SRP)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class Report:
|
|
|
+ """负责数据逻辑的类"""
|
|
|
+ def __init__(self, data: List[float]):
|
|
|
+ self.data = data
|
|
|
+
|
|
|
+ def calculate_summary(self) -> float:
|
|
|
+ return sum(self.data) / len(self.data) if self.data else 0.0
|
|
|
+
|
|
|
+class PDFExporter:
|
|
|
+ """负责 PDF 导出的类"""
|
|
|
+ def export(self, report: Report, filepath: str):
|
|
|
+ summary = report.calculate_summary()
|
|
|
+ print(f"[PDF] 导出摘要: {summary} 到文件: {filepath}")
|
|
|
+
|
|
|
+class HTMLExporter:
|
|
|
+ """负责 HTML 导出的类"""
|
|
|
+ def export(self, report: Report, filepath: str):
|
|
|
+ summary = report.calculate_summary()
|
|
|
+ print(f"[HTML] 导出摘要: {summary} 到文件: {filepath}")
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 2. 开放-封闭原则 (Open-Closed Principle, OCP)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class Shape(ABC):
|
|
|
+ @abstractmethod
|
|
|
+ def area(self) -> float:
|
|
|
+ pass
|
|
|
+
|
|
|
+class Rectangle(Shape):
|
|
|
+ def __init__(self, width: float, height: float):
|
|
|
+ self.width = width
|
|
|
+ self.height = height
|
|
|
+
|
|
|
+ def area(self) -> float:
|
|
|
+ return self.width * self.height
|
|
|
+
|
|
|
+class Circle(Shape):
|
|
|
+ def __init__(self, radius: float):
|
|
|
+ self.radius = radius
|
|
|
+
|
|
|
+ def area(self) -> float:
|
|
|
+ import math
|
|
|
+ return math.pi * (self.radius ** 2)
|
|
|
+
|
|
|
+def print_areas(shapes: List[Shape]):
|
|
|
+ """对扩展开放:可以添加新形状而无需修改此函数"""
|
|
|
+ for shape in shapes:
|
|
|
+ print(f"Shape area: {shape.area()}")
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 3. 里氏替换原则 (Liskov Substitution Principle, LSP)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class Bird(ABC):
|
|
|
+ pass
|
|
|
+
|
|
|
+class FlyingBird(Bird):
|
|
|
+ @abstractmethod
|
|
|
+ def fly(self):
|
|
|
+ pass
|
|
|
+
|
|
|
+class NonFlyingBird(Bird):
|
|
|
+ pass
|
|
|
+
|
|
|
+class Sparrow(FlyingBird):
|
|
|
+ def fly(self):
|
|
|
+ print("麻雀正在飞翔...")
|
|
|
+
|
|
|
+class Ostrich(NonFlyingBird):
|
|
|
+ def run(self):
|
|
|
+ print("鸵鸟正在奔跑...")
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 4. 依赖倒置原则 (Dependency Inversion Principle, DIP)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class MessageSender(ABC):
|
|
|
+ @abstractmethod
|
|
|
+ def send(self, message: str):
|
|
|
+ pass
|
|
|
+
|
|
|
+class EmailSender(MessageSender):
|
|
|
+ def send(self, message: str):
|
|
|
+ print(f"发送邮件通知: {message}")
|
|
|
+
|
|
|
+class SMSSender(MessageSender):
|
|
|
+ def send(self, message: str):
|
|
|
+ print(f"发送短信通知: {message}")
|
|
|
+
|
|
|
+class NotificationService:
|
|
|
+ def __init__(self, sender: MessageSender):
|
|
|
+ # 依赖于抽象接口 MessageSender,而不是具体的 EmailSender 或 SMSSender
|
|
|
+ self.sender = sender
|
|
|
+
|
|
|
+ def notify(self, message: str):
|
|
|
+ self.sender.send(message)
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 5. 接口隔离原则 (Interface Segregation Principle, ISP)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class Workable(Protocol):
|
|
|
+ def work(self) -> None: ...
|
|
|
+
|
|
|
+class Eatable(Protocol):
|
|
|
+ def eat(self) -> None: ...
|
|
|
+
|
|
|
+class Human(Workable, Eatable):
|
|
|
+ def work(self) -> None:
|
|
|
+ print("人类在工作...")
|
|
|
+
|
|
|
+ def eat(self) -> None:
|
|
|
+ print("人类在吃饭...")
|
|
|
+
|
|
|
+class Robot(Workable):
|
|
|
+ def work(self) -> None:
|
|
|
+ print("机器人在工作...")
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 6. 合成/聚合复用原则 (Composite/Aggregate Reuse Principle, CARP)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class Engine:
|
|
|
+ def start(self):
|
|
|
+ print("发动机已启动")
|
|
|
+
|
|
|
+class Car:
|
|
|
+ def __init__(self, engine: Engine):
|
|
|
+ # 使用组合而非继承
|
|
|
+ self.engine = engine
|
|
|
+
|
|
|
+ def start(self):
|
|
|
+ print("汽车准备出发...")
|
|
|
+ self.engine.start()
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 7. 迪米特法则 (Law of Demeter, LoD)
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+class Teacher:
|
|
|
+ def command(self, group_leader):
|
|
|
+ # 老师只下令给组长,不直接接触学生
|
|
|
+ group_leader.count_students()
|
|
|
+
|
|
|
+class GroupLeader:
|
|
|
+ def __init__(self, students):
|
|
|
+ self.students = students
|
|
|
+
|
|
|
+ def count_students(self):
|
|
|
+ print(f"学生总人数: {len(self.students)}")
|
|
|
+
|
|
|
+
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+# 演示运行
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ print("--- SRP ---")
|
|
|
+ my_report = Report([10.5, 20.0, 15.5])
|
|
|
+ pdf_exp = PDFExporter()
|
|
|
+ pdf_exp.export(my_report, "data.pdf")
|
|
|
+
|
|
|
+ print("\n--- OCP ---")
|
|
|
+ shapes = [Rectangle(10, 5), Circle(7)]
|
|
|
+ print_areas(shapes)
|
|
|
+
|
|
|
+ print("\n--- LSP ---")
|
|
|
+ sparrow = Sparrow()
|
|
|
+ sparrow.fly()
|
|
|
+
|
|
|
+ print("\n--- DIP ---")
|
|
|
+ service = NotificationService(SMSSender())
|
|
|
+ service.notify("您有一条新消息")
|
|
|
+
|
|
|
+ print("\n--- ISP ---")
|
|
|
+ worker = Robot()
|
|
|
+ worker.work()
|
|
|
+
|
|
|
+ print("\n--- CARP ---")
|
|
|
+ engine = Engine()
|
|
|
+ my_car = Car(engine)
|
|
|
+ my_car.start()
|
|
|
+
|
|
|
+ print("\n--- LoD ---")
|
|
|
+ students = ["Alice", "Bob", "Charlie"]
|
|
|
+ leader = GroupLeader(students)
|
|
|
+ teacher = Teacher()
|
|
|
+ teacher.command(leader)
|
|
|
+
|