面向对象设计
面向对象设计(Object-Oriented Design,OOD)是 Microsoft SDE 面试中的重要环节。面试官会要求你设计一个系统或类,考察你的面向对象设计能力、代码组织能力和问题分析能力。
OOD 设计原则
SOLID 原则
1. 单一职责原则(SRP)
一个类应该只有一个引起它变化的原因。
# 不好的设计
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def save_to_database(self):
# 保存到数据库
pass
def send_email(self):
# 发送邮件
pass
# 好的设计
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class UserRepository:
def save(self, user):
# 保存到数据库
pass
class EmailService:
def send(self, user):
# 发送邮件
pass
2. 开放封闭原则(OCP)
对扩展开放,对修改封闭。
# 不好的设计
class AreaCalculator:
def calculate(self, shape):
if isinstance(shape, Rectangle):
return shape.width * shape.height
elif isinstance(shape, Circle):
return 3.14 * shape.radius ** 2
# 好的设计
class Shape:
def area(self):
raise NotImplementedError
class Rectangle(Shape):
def area(self):
return self.width * self.height
class Circle(Shape):
def area(self):
return 3.14 * self.radius ** 2
class AreaCalculator:
def calculate(self, shape):
return shape.area()
3. 里氏替换原则(LSP)
子类对象应该能够替换父类对象。
class Bird:
def fly(self):
pass
class Sparrow(Bird):
def fly(self):
print("Sparrow flying")
class Penguin(Bird):
def fly(self):
raise NotImplementedError("Penguins can't fly")
# 更好的设计
class Bird:
pass
class FlyingBird(Bird):
def fly(self):
pass
class Sparrow(FlyingBird):
def fly(self):
print("Sparrow flying")
class Penguin(Bird):
pass # 企鹅不会飞,不需要实现 fly 方法
4. 接口隔离原则(ISP)
客户端不应该依赖它不需要的接口。
# 不好的设计
class Worker:
def work(self):
pass
def eat(self):
pass
class Human(Worker):
def work(self):
print("Human working")
def eat(self):
print("Human eating")
class Robot(Worker):
def work(self):
print("Robot working")
def eat(self):
raise NotImplementedError("Robots don't eat")
# 好的设计
class Workable:
def work(self):
raise NotImplementedError
class Eatable:
def eat(self):
raise NotImplementedError
class Human(Workable, Eatable):
def work(self):
print("Human working")
def eat(self):
print("Human eating")
class Robot(Workable):
def work(self):
print("Robot working")
5. 依赖倒置原则(DIP)
高层模块不应该依赖低层模块,两者都应该依赖抽象。
# 不好的设计
class MySQLDatabase:
def save(self, data):
print("Saving to MySQL")
class UserService:
def __init__(self):
self.db = MySQLDatabase() # 直接依赖具体实现
def save_user(self, user):
self.db.save(user)
# 好的设计
class Database:
def save(self, data):
raise NotImplementedError
class MySQLDatabase(Database):
def save(self, data):
print("Saving to MySQL")
class UserService:
def __init__(self, database: Database): # 依赖抽象
self.db = database
def save_user(self, user):
self.db.save(user)
常见设计模式
1. 单例模式(Singleton)
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# 线程安全的单例
import threading
class ThreadSafeSingleton:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
2. 工厂模式(Factory)
class Animal:
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return "Woof"
class Cat(Animal):
def speak(self):
return "Meow"
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
raise ValueError(f"Unknown animal type: {animal_type}")
3. 观察者模式(Observer)
class Observer:
def update(self, message):
raise NotImplementedError
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)
class ConcreteObserver(Observer):
def __init__(self, name):
self.name = name
def update(self, message):
print(f"{self.name} received: {message}")
常见 OOD 题目
1. 设计电梯系统
class Elevator:
def __init__(self, id, current_floor=1):
self.id = id
self.current_floor = current_floor
self.direction = 0 # -1: down, 0: idle, 1: up
self.requests = []
def move(self):
if not self.requests:
self.direction = 0
return
if self.direction == 1:
self.current_floor += 1
elif self.direction == -1:
self.current_floor -= 1
if self.current_floor in self.requests:
self.requests.remove(self.current_floor)
self.stop()
def stop(self):
print(f"Elevator {self.id} stopped at floor {self.current_floor}")
def add_request(self, floor):
if floor not in self.requests:
self.requests.append(floor)
self.requests.sort()
if floor > self.current_floor:
self.direction = 1
elif floor < self.current_floor:
self.direction = -1
class ElevatorController:
def __init__(self, num_elevators):
self.elevators = [Elevator(i) for i in range(num_elevators)]
def request_elevator(self, floor, direction):
# 选择最近的电梯
best_elevator = min(
self.elevators,
key=lambda e: abs(e.current_floor - floor)
)
best_elevator.add_request(floor)
return best_elevator
2. 设计停车场系统
from enum import Enum
class VehicleType(Enum):
MOTORCYCLE = 1
CAR = 2
BUS = 3
class Vehicle:
def __init__(self, license_plate, vehicle_type):
self.license_plate = license_plate
self.vehicle_type = vehicle_type
class ParkingSpot:
def __init__(self, spot_id, vehicle_type):
self.spot_id = spot_id
self.vehicle_type = vehicle_type
self.vehicle = None
self.is_occupied = False
def park(self, vehicle):
if self.is_occupied or vehicle.vehicle_type != self.vehicle_type:
return False
self.vehicle = vehicle
self.is_occupied = True
return True
def leave(self):
self.vehicle = None
self.is_occupied = False
class ParkingLot:
def __init__(self, num_spots_per_type):
self.spots = {}
for vehicle_type in VehicleType:
self.spots[vehicle_type] = [
ParkingSpot(f"{vehicle_type.name}_{i}", vehicle_type)
for i in range(num_spots_per_type)
]
def park_vehicle(self, vehicle):
available_spots = [
spot for spot in self.spots[vehicle.vehicle_type]
if not spot.is_occupied
]
if not available_spots:
return False
return available_spots[0].park(vehicle)
def remove_vehicle(self, vehicle):
for spots in self.spots.values():
for spot in spots:
if spot.vehicle == vehicle:
spot.leave()
return True
return False
3. 设计在线书店
class Book:
def __init__(self, isbn, title, author, price):
self.isbn = isbn
self.title = title
self.author = author
self.price = price
self.quantity = 0
class ShoppingCart:
def __init__(self):
self.items = {} # {book: quantity}
def add_item(self, book, quantity):
if book in self.items:
self.items[book] += quantity
else:
self.items[book] = quantity
def remove_item(self, book):
if book in self.items:
del self.items[book]
def get_total(self):
return sum(book.price * quantity for book, quantity in self.items.items())
class Order:
def __init__(self, order_id, cart, customer):
self.order_id = order_id
self.items = cart.items.copy()
self.customer = customer
self.total = cart.get_total()
self.status = "pending"
def process(self):
self.status = "processing"
# 处理订单逻辑
self.status = "completed"
class Customer:
def __init__(self, customer_id, name, email):
self.customer_id = customer_id
self.name = name
self.email = email
self.orders = []
def place_order(self, cart, order_id):
order = Order(order_id, cart, self)
order.process()
self.orders.append(order)
return order
class BookStore:
def __init__(self):
self.books = {} # {isbn: book}
self.customers = {} # {customer_id: customer}
def add_book(self, book):
self.books[book.isbn] = book
def search_books(self, query):
results = []
query_lower = query.lower()
for book in self.books.values():
if (query_lower in book.title.lower() or
query_lower in book.author.lower()):
results.append(book)
return results
OOD 面试技巧
1. 澄清需求
- 询问功能范围
- 确认约束条件
- 了解使用场景
2. 设计步骤
- 识别核心对象:找出系统中的主要实体
- 定义关系:确定对象之间的关系
- 设计接口:定义每个类的公共接口
- 实现细节:填充具体实现
3. 代码质量
- 清晰的命名
- 适当的注释
- 错误处理
- 可扩展性
总结
面向对象设计是面试中的重要环节:
- 设计原则:SOLID 原则指导设计
- 设计模式:单例、工厂、观察者等常见模式
- 常见题目:电梯系统、停车场、在线书店等
- 面试技巧:澄清需求、逐步设计、注重代码质量
掌握 OOD 设计能够帮助你设计出清晰、可维护的系统。
接下来,让我们学习系统设计,这是高级工程师面试的重要环节。
