0%

下面我将通过详细的 Python 代码示例,深入讲解每个面向对象的最佳实践原则。

1. 优先使用组合而非继承

问题示例(使用继承)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary

def calculate_bonus(self):
return self.salary * 0.1

# 不恰当使用继承 - Manager "是一个" Employee,但添加了团队管理功能
class Manager(Employee):
def __init__(self, name, salary, team_size):
super().__init__(name, salary)
self.team_size = team_size

def manage_team(self):
print(f"{self.name} is managing a team of {self.team_size} people")

# 问题:当需要添加不同行为时,继承层次会变得复杂

解决方案(使用组合)

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
class BonusCalculator:
@staticmethod
def calculate(salary):
return salary * 0.1

class TeamManager:
def __init__(self, team_size):
self.team_size = team_size

def manage(self, name):
print(f"{name} is managing a team of {self.team_size} people")

class Employee:
def __init__(self, name, salary, bonus_calculator=None):
self.name = name
self.salary = salary
self.bonus_calculator = bonus_calculator or BonusCalculator()

def calculate_bonus(self):
return self.bonus_calculator.calculate(self.salary)

class Manager:
def __init__(self, name, salary, team_size):
self.employee = Employee(name, salary)
self.team_manager = TeamManager(team_size)

def calculate_bonus(self):
return self.employee.calculate_bonus()

def manage_team(self):
self.team_manager.manage(self.employee.name)

# 更灵活,可以动态更换组件
manager = Manager("Alice", 80000, 5)
manager.manage_team()
print(f"Bonus: {manager.calculate_bonus()}")

2. 遵循最小知识原则(迪米特法则)

问题示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Address:
def __init__(self, city, street):
self.city = city
self.street = street

class Person:
def __init__(self, name, address):
self.name = name
self.address = address

def get_address(self):
return self.address

# 违反迪米特法则
person = Person("Bob", Address("Beijing", "Main St"))
print(person.get_address().city) # 直接访问Address的属性

解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person:
def __init__(self, name, address):
self.name = name
self._address = address # 设为私有

def get_city(self):
return self._address.city

def get_street(self):
return self._address.street

# 客户端代码
person = Person("Bob", Address("Beijing", "Main St"))
print(person.get_city()) # 只与Person交互

3. 保持类和方法的小型化

问题示例(大类)

1
2
3
4
5
6
7
8
class ReportGenerator:
def generate_report(self, data):
# 步骤1: 验证数据 (20行代码)
# 步骤2: 处理数据 (50行代码)
# 步骤3: 生成报告 (40行代码)
# 步骤4: 保存报告 (30行代码)
# 总计: 140+行代码
pass

解决方案(分解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DataValidator:
def validate(self, data): pass

class DataProcessor:
def process(self, data): pass

class ReportBuilder:
def build(self, processed_data): pass

class ReportSaver:
def save(self, report): pass

class ReportGenerator:
def __init__(self):
self.validator = DataValidator()
self.processor = DataProcessor()
self.builder = ReportBuilder()
self.saver = ReportSaver()

def generate_report(self, data):
self.validator.validate(data)
processed_data = self.processor.process(data)
report = self.builder.build(processed_data)
self.saver.save(report)

4. 使用有意义的名字

差的名字

1
2
3
4
5
6
def p(d):  # 无意义缩写
return d * 1.1

class M: # 含糊不清
def c(self, x): # 不知道是计算什么
return x * 2

好的名字

1
2
3
4
5
6
def calculate_price_with_tax(price):
return price * 1.1

class ShoppingCart:
def calculate_total(self, items):
return sum(item.price for item in items)

5. 合理使用访问修饰符

Python 使用命名约定实现访问控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # 公开属性
self._balance = balance # 保护属性 (约定)
self.__secret_code = 123 # 私有属性 (名称修饰)

# 公开方法
def deposit(self, amount):
if amount > 0:
self._balance += amount

# 保护方法
def _validate_amount(self, amount):
return amount > 0

# 私有方法
def __generate_statement(self):
return f"Statement for {self.owner}"

account = BankAccount("Alice", 1000)
print(account.owner) # 可以访问
print(account._balance) # 可以访问但不应该
# print(account.__secret_code) # 会报错

6. 避免上帝对象

问题示例

1
2
3
4
5
6
7
8
9
10
11
class GodObject:
def __init__(self):
self.users = []
self.products = []
self.orders = []

def add_user(self, user): pass
def delete_user(self, user_id): pass
def add_product(self, product): pass
def process_order(self, order): pass
# ... 50多个方法

解决方案(分解责任)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class UserManager:
def __init__(self):
self.users = []

def add_user(self, user): pass
def delete_user(self, user_id): pass

class ProductCatalog:
def __init__(self):
self.products = []

def add_product(self, product): pass

class OrderProcessor:
def process_order(self, order): pass

# 使用组合
class ECommerceSystem:
def __init__(self):
self.user_manager = UserManager()
self.product_catalog = ProductCatalog()
self.order_processor = OrderProcessor()

7. 合理使用接口和抽象类

Python 使用 abc 模块实现抽象基类:

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
from abc import ABC, abstractmethod

# 接口
class Renderable(ABC):
@abstractmethod
def render(self):
pass

# 抽象类
class Shape(ABC):
def __init__(self, color):
self.color = color

@abstractmethod
def area(self):
pass

def describe(self):
print(f"This is a {self.color} shape")

# 具体类
class Circle(Shape, Renderable):
def __init__(self, color, radius):
super().__init__(color)
self.radius = radius

def area(self):
return 3.14 * self.radius ** 2

def render(self):
print(f"Rendering a {self.color} circle with radius {self.radius}")

# 使用
circle = Circle("red", 5)
circle.describe()
print("Area:", circle.area())
circle.render()

这些最佳实践结合起来,可以帮助你编写出更健壮、更易维护的面向对象 Python 代码。记住要根据具体情况灵活应用这些原则,而不是机械地遵循。