LuTong vor 2 Monaten
Commit
8504e5d966
2 geänderte Dateien mit 440 neuen und 0 gelöschten Zeilen
  1. 232 0
      design_pattern/design_principles.md
  2. 208 0
      design_pattern/lec3_design_principle.py

+ 232 - 0
design_pattern/design_principles.md

@@ -0,0 +1,232 @@
+# 设计原则 (Design Principles)
+
+本文档整理了面向对象设计的核心设计原则,并配以 Python 示例代码,旨在提高软件的可维护性、可复用性和灵活性。
+
+---
+
+## 1. 单一职责原则 (Single Responsibility Principle, SRP)
+
+**定义**:一个类或模块应当有且只有一个引起它变化的原因。简单来说,一个类只负责一项职责。
+
+**好处**:
+- 降低类的复杂度。
+- 提高类的可读性和可维护性。
+- 降低变更引起的风险。
+
+**Python 示例**:
+
+```python
+# 违反 SRP 的写法:一个类既负责统计又负责输出
+class Report:
+    def __init__(self, data):
+        self.data = data
+
+    def calculate_summary(self):
+        return sum(self.data) / len(self.data)
+
+    def export_pdf(self):
+        print("Exporting to PDF...")
+
+# 遵循 SRP 的写法:将统计和输出分离
+class Report:
+    def __init__(self, data):
+        self.data = data
+
+    def calculate_summary(self):
+        return sum(self.data) / len(self.data)
+
+class PDFExporter:
+    def export(self, report):
+        print(f"Exporting summary {report.calculate_summary()} to PDF...")
+```
+
+---
+
+## 2. 开放-封闭原则 (Open-Closed Principle, OCP)
+
+**定义**:软件实体(类、模块、函数等)应当对扩展开放,对修改封闭。即在不修改原有代码的基础上,通过扩展来增加新功能。
+
+**好处**:
+- 提高系统的可复用性。
+- 提高系统的可维护性。
+
+**Python 示例**:
+
+```python
+from abc import ABC, abstractmethod
+
+class Shape(ABC):
+    @abstractmethod
+    def area(self):
+        pass
+
+class Rectangle(Shape):
+    def __init__(self, width, height):
+        self.width = width
+        self.height = height
+    def area(self):
+        return self.width * self.height
+
+class Circle(Shape):
+    def __init__(self, radius):
+        self.radius = radius
+    def area(self):
+        return 3.14 * (self.radius ** 2)
+
+def calculate_total_area(shapes):
+    return sum(shape.area() for shape in shapes)
+```
+
+---
+
+## 3. 里氏替换原则 (Liskov Substitution Principle, LSP)
+
+**定义**:子类必须能够替换掉它们的父类,且程序的行为保持不变。
+
+**核心**:子类不能违反父类定义的契约(协议)。
+
+**Python 示例**:
+
+```python
+class Bird:
+    def fly(self):
+        print("Flying...")
+
+class Sparrow(Bird):
+    def fly(self):
+        print("Sparrow flying...")
+
+# 鸵鸟不会飞,如果强行继承 Bird 并重写 fly 抛错,则违反 LSP
+class Ostrich(Bird):
+    def fly(self):
+        raise Exception("Ostrich cannot fly")
+
+# 重构:将飞行的行为提取出来
+class Bird(ABC):
+    pass
+
+class FlyingBird(Bird):
+    def fly(self):
+        print("Flying...")
+
+class Sparrow(FlyingBird):
+    pass
+
+class Ostrich(Bird):
+    pass
+```
+
+---
+
+## 4. 依赖倒置原则 (Dependency Inversion Principle, DIP)
+
+**定义**:
+1. 高层模块不应依赖低层模块,两者都应依赖其抽象。
+2. 抽象不应依赖细节,细节应依赖抽象。
+
+**好处**:
+- 降低耦合度。
+- 增强系统的灵活性和可测试性。
+
+**Python 示例**:
+
+```python
+from abc import ABC, abstractmethod
+
+class MessageSender(ABC):
+    @abstractmethod
+    def send(self, message):
+        pass
+
+class EmailSender(MessageSender):
+    def send(self, message):
+        print(f"Sending email: {message}")
+
+class NotificationService:
+    def __init__(self, sender: MessageSender):
+        self.sender = sender  # 依赖于抽象
+
+    def notify(self, message):
+        self.sender.send(message)
+```
+
+---
+
+## 5. 接口隔离原则 (Interface Segregation Principle, ISP)
+
+**定义**:不应该强迫客户端依赖于它们不使用的接口。接口应当尽量细化,一个类对另一个类的依赖应该建立在最小的接口上。
+
+**Python 示例**:
+
+```python
+from abc import ABC, abstractmethod
+
+# 违反 ISP:一个接口包含了所有动作
+class Worker(ABC):
+    @abstractmethod
+    def work(self): pass
+    @abstractmethod
+    def eat(self): pass
+
+# 遵循 ISP:拆分为更细的接口
+class Workable(ABC):
+    @abstractmethod
+    def work(self): pass
+
+class Eatable(ABC):
+    @abstractmethod
+    def eat(self): pass
+
+class Robot(Workable):
+    def work(self):
+        print("Robot working...")
+
+class Human(Workable, Eatable):
+    def work(self):
+        print("Human working...")
+    def eat(self):
+        print("Human eating...")
+```
+
+---
+
+## 6. 合成/聚合复用原则 (Composite/Aggregate Reuse Principle, CARP)
+
+**定义**:尽量使用组合(Composition)或聚合(Aggregation),少用继承(Inheritance)。
+
+**核心**:继承会破坏封装性(白盒复用),而组合通过委托实现功能复用(黑盒复用),耦合度更低。
+
+**Python 示例**:
+
+```python
+class Engine:
+    def start(self):
+        print("Engine starting...")
+
+class Car:
+    def __init__(self):
+        self.engine = Engine() # 组合
+
+    def start(self):
+        print("Car starting...")
+        self.engine.start()
+```
+
+---
+
+## 7. 迪米特法则 (Law of Demeter, LoD / Least Knowledge Principle)
+
+**定义**:一个对象应当对其他对象有尽可能少的了解。只与直接的朋友通信。
+
+**直接的朋友**:
+- 该对象本身。
+- 成员变量。
+- 方法参数。
+- 方法内创建的对象。
+
+---
+
+## 总结
+
+这些设计原则(SOLID + CARP + LoD)是设计模式的基石。在实际开发中,应根据具体业务场景灵活应用,过度设计往往适得其反,核心目标是:**高内聚、低耦合**。
+

+ 208 - 0
design_pattern/lec3_design_principle.py

@@ -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)
+