名称: oop-继承-组合 用户可调用: false 描述: 在面向对象设计中决定使用继承还是组合时使用。当创建类层次结构或从较小组件组合对象时使用。 允许的工具:
- Bash
- Read
OOP 继承与组合
掌握继承和组合以构建灵活、可维护的面向对象系统。此技能侧重于理解何时使用继承与组合以及如何有效应用每种方法。
继承基础
Java 中的基本继承
// 具有共同行为的基类
public abstract class Vehicle {
private String brand;
private String model;
private int year;
protected double currentSpeed;
protected Vehicle(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
this.currentSpeed = 0.0;
}
// 模板方法模式
public final void start() {
performSafetyCheck();
startEngine();
System.out.println(brand + " " + model + " started");
}
// 子类的钩子方法
protected void performSafetyCheck() {
System.out.println("执行基本安全检查");
}
// 抽象方法 - 必须实现
protected abstract void startEngine();
public void accelerate(double speed) {
currentSpeed += speed;
System.out.println("当前速度: " + currentSpeed);
}
public void brake(double reduction) {
currentSpeed = Math.max(0, currentSpeed - reduction);
System.out.println("当前速度: " + currentSpeed);
}
// Getter 方法
public String getBrand() { return brand; }
public String getModel() { return model; }
public int getYear() { return year; }
public double getCurrentSpeed() { return currentSpeed; }
}
// 具体实现
public class Car extends Vehicle {
private int numberOfDoors;
private boolean isSunroofOpen;
public Car(String brand, String model, int year, int numberOfDoors) {
super(brand, model, year);
this.numberOfDoors = numberOfDoors;
this.isSunroofOpen = false;
}
@Override
protected void startEngine() {
System.out.println("汽车引擎通过点火启动");
}
@Override
protected void performSafetyCheck() {
super.performSafetyCheck();
System.out.println("检查车门是否关闭");
System.out.println("检查安全带");
}
public void openSunroof() {
if (currentSpeed == 0) {
isSunroofOpen = true;
System.out.println("天窗打开");
} else {
System.out.println("停车后再打开天窗");
}
}
public int getNumberOfDoors() {
return numberOfDoors;
}
}
// 另一个具体实现
public class Motorcycle extends Vehicle {
private boolean hasWindshield;
public Motorcycle(String brand, String model, int year, boolean hasWindshield) {
super(brand, model, year);
this.hasWindshield = hasWindshield;
}
@Override
protected void startEngine() {
System.out.println("摩托车引擎通过踢/按钮启动");
}
@Override
public void accelerate(double speed) {
// 重写以添加摩托车特定行为
if (currentSpeed + speed > 200) {
System.out.println("警告: 超过最大安全速度!");
}
super.accelerate(speed);
}
public boolean hasWindshield() {
return hasWindshield;
}
}
Python 中的继承
from abc import ABC, abstractmethod
from typing import List, Optional
from datetime import datetime
class Employee(ABC):
"""所有员工的抽象基类。"""
def __init__(self, employee_id: str, name: str, email: str, hire_date: datetime):
self._employee_id = employee_id
self._name = name
self._email = email
self._hire_date = hire_date
self._is_active = True
@property
def employee_id(self) -> str:
return self._employee_id
@property
def name(self) -> str:
return self._name
@property
def email(self) -> str:
return self._email
@property
def hire_date(self) -> datetime:
return self._hire_date
@property
def years_of_service(self) -> int:
return (datetime.now() - self._hire_date).days // 365
# 模板方法
def process_payroll(self) -> float:
"""处理工资单 - 模板方法。"""
if not self._is_active:
raise ValueError("无法为不活跃员工处理工资单")
base_pay = self.calculate_pay()
bonus = self.calculate_bonus()
deductions = self.calculate_deductions()
total_pay = base_pay + bonus - deductions
self.record_payment(total_pay)
return total_pay
# 抽象方法 - 必须由子类实现
@abstractmethod
def calculate_pay(self) -> float:
"""计算基本工资。"""
pass
# 带有默认实现的钩子方法
def calculate_bonus(self) -> float:
"""计算奖金 - 可以重写。"""
return 0.0
def calculate_deductions(self) -> float:
"""计算扣除额 - 可以重写。"""
return 0.0
def record_payment(self, amount: float) -> None:
"""记录付款。"""
print(f"为 {self._name} 记录 ${amount:.2f} 的付款")
def deactivate(self) -> None:
"""停用员工。"""
self._is_active = False
class SalariedEmployee(Employee):
"""按固定薪水支付的员工。"""
def __init__(
self,
employee_id: str,
name: str,
email: str,
hire_date: datetime,
annual_salary: float
):
super().__init__(employee_id, name, email, hire_date)
self._annual_salary = annual_salary
def calculate_pay(self) -> float:
"""计算月薪。"""
return self._annual_salary / 12
def calculate_bonus(self) -> float:
"""基于服务年限的年度奖金。"""
return self._annual_salary * 0.01 * self.years_of_service
class HourlyEmployee(Employee):
"""按小时支付的员工。"""
def __init__(
self,
employee_id: str,
name: str,
email: str,
hire_date: datetime,
hourly_rate: float
):
super().__init__(employee_id, name, email, hire_date)
self._hourly_rate = hourly_rate
self._hours_worked = 0.0
def log_hours(self, hours: float) -> None:
"""记录本周期工作小时数。"""
if hours < 0:
raise ValueError("小时数不能为负")
self._hours_worked += hours
def calculate_pay(self) -> float:
"""基于工作小时数计算工资。"""
regular_hours = min(self._hours_worked, 40)
overtime_hours = max(0, self._hours_worked - 40)
regular_pay = regular_hours * self._hourly_rate
overtime_pay = overtime_hours * self._hourly_rate * 1.5
return regular_pay + overtime_pay
def record_payment(self, amount: float) -> None:
"""记录付款并重置小时数。"""
super().record_payment(amount)
self._hours_worked = 0.0
class CommissionEmployee(SalariedEmployee):
"""带基本薪水和佣金的员工。"""
def __init__(
self,
employee_id: str,
name: str,
email: str,
hire_date: datetime,
annual_salary: float,
commission_rate: float
):
super().__init__(employee_id, name, email, hire_date, annual_salary)
self._commission_rate = commission_rate
self._sales_this_period = 0.0
def record_sale(self, amount: float) -> None:
"""记录销售以计算佣金。"""
if amount <= 0:
raise ValueError("销售金额必须为正")
self._sales_this_period += amount
def calculate_pay(self) -> float:
"""计算基本薪水加佣金。"""
base = super().calculate_pay()
commission = self._sales_this_period * self._commission_rate
return base + commission
def record_payment(self, amount: float) -> None:
"""记录付款并重置销售。"""
super().record_payment(amount)
self._sales_this_period = 0.0
TypeScript 中的继承
// 抽象基类
abstract class Shape {
protected readonly id: string;
protected color: string;
constructor(color: string) {
this.id = crypto.randomUUID();
this.color = color;
}
// 抽象方法
abstract area(): number;
abstract perimeter(): number;
abstract draw(): void;
// 具体方法
getColor(): string {
return this.color;
}
setColor(color: string): void {
this.color = color;
}
describe(): string {
return `${this.constructor.name} (${this.color}): 面积 = ${this.area().toFixed(2)}, 周长 = ${this.perimeter().toFixed(2)}`;
}
}
// 具体实现
class Circle extends Shape {
private radius: number;
constructor(color: string, radius: number) {
super(color);
if (radius <= 0) {
throw new Error("半径必须为正");
}
this.radius = radius;
}
area(): number {
return Math.PI * this.radius ** 2;
}
perimeter(): number {
return 2 * Math.PI * this.radius;
}
draw(): void {
console.log(`绘制一个 ${this.color} 的圆形,半径为 ${this.radius}`);
}
getRadius(): number {
return this.radius;
}
}
class Rectangle extends Shape {
private width: number;
private height: number;
constructor(color: string, width: number, height: number) {
super(color);
if (width <= 0 || height <= 0) {
throw new Error("尺寸必须为正");
}
this.width = width;
this.height = height;
}
area(): number {
return this.width * this.height;
}
perimeter(): number {
return 2 * (this.width + this.height);
}
draw(): void {
console.log(`绘制一个 ${this.color} 的矩形 ${this.width}x${this.height}`);
}
isSquare(): boolean {
return this.width === this.height;
}
}
class Triangle extends Shape {
private sideA: number;
private sideB: number;
private sideC: number;
constructor(color: string, sideA: number, sideB: number, sideC: number) {
super(color);
if (!this.isValidTriangle(sideA, sideB, sideC)) {
throw new Error("无效的三角形尺寸");
}
this.sideA = sideA;
this.sideB = sideB;
this.sideC = sideC;
}
private isValidTriangle(a: number, b: number, c: number): boolean {
return a + b > c && b + c > a && a + c > b;
}
area(): number {
// 海伦公式
const s = this.perimeter() / 2;
return Math.sqrt(s * (s - this.sideA) * (s - this.sideB) * (s - this.sideC));
}
perimeter(): number {
return this.sideA + this.sideB + this.sideC;
}
draw(): void {
console.log(`绘制一个 ${this.color} 的三角形`);
}
}
组合优先于继承
Java 中的组合
// 组件接口
interface Engine {
void start();
void stop();
int getHorsepower();
}
interface Transmission {
void shiftUp();
void shiftDown();
String getType();
}
interface GPS {
void navigate(String destination);
String getCurrentLocation();
}
// 具体组件实现
class V6Engine implements Engine {
private final int horsepower;
private boolean running;
public V6Engine(int horsepower) {
this.horsepower = horsepower;
this.running = false;
}
@Override
public void start() {
running = true;
System.out.println("V6 引擎启动");
}
@Override
public void stop() {
running = false;
System.out.println("V6 引擎停止");
}
@Override
public int getHorsepower() {
return horsepower;
}
}
class ElectricEngine implements Engine {
private final int horsepower;
private boolean running;
private int batteryLevel;
public ElectricEngine(int horsepower) {
this.horsepower = horsepower;
this.batteryLevel = 100;
this.running = false;
}
@Override
public void start() {
if (batteryLevel > 0) {
running = true;
System.out.println("电动引擎静音启动");
} else {
System.out.println("电池耗尽!");
}
}
@Override
public void stop() {
running = false;
System.out.println("电动引擎停止");
}
@Override
public int getHorsepower() {
return horsepower;
}
public int getBatteryLevel() {
return batteryLevel;
}
}
class AutomaticTransmission implements Transmission {
private int currentGear;
public AutomaticTransmission() {
this.currentGear = 1;
}
@Override
public void shiftUp() {
if (currentGear < 8) {
currentGear++;
System.out.println("自动切换到齿轮 " + currentGear);
}
}
@Override
public void shiftDown() {
if (currentGear > 1) {
currentGear--;
System.out.println("自动切换到齿轮 " + currentGear);
}
}
@Override
public String getType() {
return "自动";
}
}
class ManualTransmission implements Transmission {
private int currentGear;
public ManualTransmission() {
this.currentGear = 1;
}
@Override
public void shiftUp() {
if (currentGear < 6) {
currentGear++;
System.out.println("手动切换到齿轮 " + currentGear);
}
}
@Override
public void shiftDown() {
if (currentGear > 1) {
currentGear--;
System.out.println("手动切换到齿轮 " + currentGear);
}
}
@Override
public String getType() {
return "手动";
}
}
// 组合的汽车类
public class ComposedCar {
private final Engine engine;
private final Transmission transmission;
private final GPS gps; // 可选组件
private final String brand;
private final String model;
// 用于灵活构建的建造者
public static class Builder {
private Engine engine;
private Transmission transmission;
private GPS gps;
private String brand;
private String model;
public Builder brand(String brand) {
this.brand = brand;
return this;
}
public Builder model(String model) {
this.model = model;
return this;
}
public Builder engine(Engine engine) {
this.engine = engine;
return this;
}
public Builder transmission(Transmission transmission) {
this.transmission = transmission;
return this;
}
public Builder gps(GPS gps) {
this.gps = gps;
return this;
}
public ComposedCar build() {
if (engine == null || transmission == null) {
throw new IllegalStateException("需要引擎和变速器");
}
return new ComposedCar(this);
}
}
private ComposedCar(Builder builder) {
this.engine = builder.engine;
this.transmission = builder.transmission;
this.gps = builder.gps;
this.brand = builder.brand;
this.model = builder.model;
}
// 委托给组件
public void start() {
engine.start();
System.out.println(brand + " " + model + " 准备驾驶");
}
public void stop() {
engine.stop();
}
public void shiftUp() {
transmission.shiftUp();
}
public void shiftDown() {
transmission.shiftDown();
}
public void navigateTo(String destination) {
if (gps != null) {
gps.navigate(destination);
} else {
System.out.println("GPS 不可用");
}
}
public String getSpecs() {
return String.format("%s %s - %d HP %s 变速器",
brand, model, engine.getHorsepower(), transmission.getType());
}
}
// 使用
ComposedCar sportsCar = new ComposedCar.Builder()
.brand("保时捷")
.model("911")
.engine(new V6Engine(450))
.transmission(new ManualTransmission())
.build();
ComposedCar electricCar = new ComposedCar.Builder()
.brand("特斯拉")
.model("Model 3")
.engine(new ElectricEngine(283))
.transmission(new AutomaticTransmission())
.build();
Python 中的组合
from typing import Protocol, List, Optional
from dataclasses import dataclass
# 组件协议(接口)
class Renderer(Protocol):
"""渲染组件的协议。"""
def render(self, content: str) -> str: ...
class Logger(Protocol):
"""日志组件的协议。"""
def log(self, message: str, level: str) -> None: ...
class Validator(Protocol):
"""验证组件的协议。"""
def validate(self, data: dict) -> bool: ...
def get_errors(self) -> List[str]: ...
# 具体组件实现
class HTMLRenderer:
"""将内容渲染为 HTML。"""
def render(self, content: str) -> str:
return f"<html><body>{content}</body></html>"
class MarkdownRenderer:
"""将内容渲染为 Markdown。"""
def render(self, content: str) -> str:
return f"# {content}
渲染为 Markdown"
class FileLogger:
"""将消息记录到文件。"""
def __init__(self, filename: str):
self.filename = filename
def log(self, message: str, level: str) -> None:
with open(self.filename, 'a') as f:
f.write(f"[{level}] {message}
")
class ConsoleLogger:
"""将消息记录到控制台。"""
def log(self, message: str, level: str) -> None:
print(f"[{level}] {message}")
class EmailValidator:
"""验证电子邮件地址。"""
def __init__(self):
self.errors: List[str] = []
def validate(self, data: dict) -> bool:
self.errors = []
email = data.get('email', '')
if not email:
self.errors.append("电子邮件必填")
return False
if '@' not in email:
self.errors.append("电子邮件必须包含 @")
return False
if '.' not in email.split('@')[1]:
self.errors.append("电子邮件必须有有效域名")
return False
return True
def get_errors(self) -> List[str]:
return self.errors
# 使用依赖注入的组合类
class UserService:
"""由各种组件组成的服务。"""
def __init__(
self,
renderer: Renderer,
logger: Logger,
validator: Validator
):
self._renderer = renderer
self._logger = logger
self._validator = validator
def create_user(self, user_data: dict) -> Optional[str]:
"""使用组合组件创建用户。"""
self._logger.log(f"创建用户: {user_data.get('email')}", "INFO")
# 使用验证器组件
if not self._validator.validate(user_data):
errors = self._validator.get_errors()
self._logger.log(f"验证失败: {errors}", "ERROR")
return None
# 处理用户创建
user_content = f"用户已创建: {user_data['email']}"
# 使用渲染器组件
rendered = self._renderer.render(user_content)
self._logger.log("用户创建成功", "INFO")
return rendered
# 运行时组件交换
class CompositeLogger:
"""委托给多个日志记录器的日志记录器。"""
def __init__(self, loggers: List[Logger]):
self._loggers = loggers
def log(self, message: str, level: str) -> None:
for logger in self._loggers:
logger.log(message, level)
def add_logger(self, logger: Logger) -> None:
self._loggers.append(logger)
# 不同组合的使用
html_service = UserService(
renderer=HTMLRenderer(),
logger=ConsoleLogger(),
validator=EmailValidator()
)
markdown_service = UserService(
renderer=MarkdownRenderer(),
logger=CompositeLogger([ConsoleLogger(), FileLogger('app.log')]),
validator=EmailValidator()
)
C# 中带组合的策略模式
// 策略接口
public interface IPaymentStrategy
{
PaymentResult ProcessPayment(decimal amount);
bool IsAvailable();
}
public interface IShippingStrategy
{
decimal CalculateCost(decimal weight, string destination);
int EstimateDeliveryDays();
}
public interface IDiscountStrategy
{
decimal ApplyDiscount(decimal originalPrice);
}
// 具体策略
public class CreditCardPayment : IPaymentStrategy
{
private readonly string _cardNumber;
private readonly string _cvv;
public CreditCardPayment(string cardNumber, string cvv)
{
_cardNumber = cardNumber;
_cvv = cvv;
}
public PaymentResult ProcessPayment(decimal amount)
{
// 信用卡处理逻辑
Console.WriteLine($"处理 ${amount} 通过信用卡");
return PaymentResult.Success(Guid.NewGuid().ToString());
}
public bool IsAvailable() => true;
}
public class PayPalPayment : IPaymentStrategy
{
private readonly string _email;
public PayPalPayment(string email)
{
_email = email;
}
public PaymentResult ProcessPayment(decimal amount)
{
Console.WriteLine($"处理 ${amount} 通过 PayPal");
return PaymentResult.Success(Guid.NewGuid().ToString());
}
public bool IsAvailable() => true;
}
public class StandardShipping : IShippingStrategy
{
public decimal CalculateCost(decimal weight, string destination)
{
return weight * 2.5m;
}
public int EstimateDeliveryDays() => 7;
}
public class ExpressShipping : IShippingStrategy
{
public decimal CalculateCost(decimal weight, string destination)
{
return weight * 5.0m;
}
public int EstimateDeliveryDays() => 2;
}
public class PercentageDiscount : IDiscountStrategy
{
private readonly decimal _percentage;
public PercentageDiscount(decimal percentage)
{
_percentage = percentage;
}
public decimal ApplyDiscount(decimal originalPrice)
{
return originalPrice * (1 - _percentage / 100);
}
}
public class FixedAmountDiscount : IDiscountStrategy
{
private readonly decimal _amount;
public FixedAmountDiscount(decimal amount)
{
_amount = amount;
}
public decimal ApplyDiscount(decimal originalPrice)
{
return Math.Max(0, originalPrice - _amount);
}
}
// 组合的订单处理器
public class OrderProcessor
{
private IPaymentStrategy _paymentStrategy;
private IShippingStrategy _shippingStrategy;
private IDiscountStrategy? _discountStrategy;
public OrderProcessor(
IPaymentStrategy paymentStrategy,
IShippingStrategy shippingStrategy,
IDiscountStrategy? discountStrategy = null)
{
_paymentStrategy = paymentStrategy ?? throw new ArgumentNullException(nameof(paymentStrategy));
_shippingStrategy = shippingStrategy ?? throw new ArgumentNullException(nameof(shippingStrategy));
_discountStrategy = discountStrategy;
}
// 策略可在运行时更改
public void SetPaymentStrategy(IPaymentStrategy strategy)
{
_paymentStrategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
}
public void SetShippingStrategy(IShippingStrategy strategy)
{
_shippingStrategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
}
public void SetDiscountStrategy(IDiscountStrategy? strategy)
{
_discountStrategy = strategy;
}
public OrderResult ProcessOrder(Order order)
{
// 计算总计
decimal subtotal = order.Items.Sum(item => item.Price * item.Quantity);
// 应用折扣
decimal total = _discountStrategy?.ApplyDiscount(subtotal) ?? subtotal;
// 计算运费
decimal shippingCost = _shippingStrategy.CalculateCost(order.TotalWeight, order.Destination);
total += shippingCost;
// 处理付款
if (!_paymentStrategy.IsAvailable())
{
return OrderResult.Failed("付款方式不可用");
}
var paymentResult = _paymentStrategy.ProcessPayment(total);
if (!paymentResult.IsSuccess)
{
return OrderResult.Failed("付款失败");
}
return OrderResult.Success(
order.Id,
total,
_shippingStrategy.EstimateDeliveryDays()
);
}
}
// 使用
var processor = new OrderProcessor(
new CreditCardPayment("1234-5678-9012-3456", "123"),
new StandardShipping(),
new PercentageDiscount(10)
);
// 运行时更改策略
processor.SetShippingStrategy(new ExpressShipping());
processor.SetDiscountStrategy(new FixedAmountDiscount(20));
混合模式
Python 中的混合
from typing import Any
import json
# 提供特定功能的混合类
class JsonSerializableMixin:
"""添加 JSON 序列化的混合。"""
def to_json(self) -> str:
"""将对象序列化为 JSON。"""
return json.dumps(self.__dict__)
@classmethod
def from_json(cls, json_str: str) -> Any:
"""从 JSON 反序列化。"""
data = json.loads(json_str)
return cls(**data)
class TimestampMixin:
"""添加时间戳跟踪的混合。"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.created_at = datetime.now()
self.updated_at = datetime.now()
def touch(self) -> None:
"""更新 updated_at 时间戳。"""
self.updated_at = datetime.now()
class ValidationMixin:
"""添加验证能力的混合。"""
def validate(self) -> bool:
"""验证对象状态。"""
errors = self.get_validation_errors()
return len(errors) == 0
def get_validation_errors(self) -> List[str]:
"""获取验证错误列表。"""
errors = []
for attr_name, attr_value in self.__dict__.items():
if attr_value is None and not attr_name.startswith('_'):
errors.append(f"{attr_name} 必填")
return errors
class AuditMixin:
"""添加审计追踪的混合。"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._changes: List[dict] = []
def record_change(self, field: str, old_value: Any, new_value: Any) -> None:
"""记录变更到审计追踪。"""
self._changes.append({
'field': field,
'old_value': old_value,
'new_value': new_value,
'timestamp': datetime.now()
})
def get_audit_trail(self) -> List[dict]:
"""获取审计追踪。"""
return self._changes.copy()
# 结合混合的基类
class User(TimestampMixin, JsonSerializableMixin, ValidationMixin, AuditMixin):
"""具有多种混合行为的用户类。"""
def __init__(self, username: str, email: str, age: int):
super().__init__()
self._username = username
self._email = email
self._age = age
@property
def username(self) -> str:
return self._username
@username.setter
def username(self, value: str) -> None:
old_value = self._username
self._username = value
self.touch()
self.record_change('username', old_value, value)
@property
def email(self) -> str:
return self._email
@email.setter
def email(self, value: str) -> None:
old_value = self._email
self._email = value
self.touch()
self.record_change('email', old_value, value)
def get_validation_errors(self) -> List[str]:
"""重写以添加特定验证。"""
errors = super().get_validation_errors()
if len(self._username) < 3:
errors.append("用户名必须至少 3 个字符")
if '@' not in self._email:
errors.append("电子邮件必须有效")
if self._age < 18:
errors.append("用户必须至少 18 岁")
return errors
# 使用
user = User("john_doe", "john@example.com", 25)
user.username = "jane_doe"
print(user.to_json())
print(user.get_audit_trail())
print(user.validate())
接口隔离
Java 中的多接口
// 隔离的接口 - 客户端仅依赖所需部分
interface Readable {
String read();
}
interface Writable {
void write(String content);
}
interface Appendable {
void append(String content);
}
interface Searchable {
List<String> search(String query);
}
// 只读文档
class ReadOnlyDocument implements Readable {
private final String content;
public ReadOnlyDocument(String content) {
this.content = content;
}
@Override
public String read() {
return content;
}
}
// 全功能文档
class Document implements Readable, Writable, Appendable, Searchable {
private StringBuilder content;
public Document(String initialContent) {
this.content = new StringBuilder(initialContent);
}
@Override
public String read() {
return content.toString();
}
@Override
public void write(String newContent) {
content = new StringBuilder(newContent);
}
@Override
public void append(String additionalContent) {
content.append(additionalContent);
}
@Override
public List<String> search(String query) {
List<String> results = new ArrayList<>();
String[] lines = content.toString().split("
");
for (String line : lines) {
if (line.contains(query)) {
results.add(line);
}
}
return results;
}
}
// 仅需要读取的客户端
class DocumentViewer {
private final Readable document;
public DocumentViewer(Readable document) {
this.document = document;
}
public void display() {
System.out.println(document.read());
}
}
// 需要读取和搜索的客户端
class DocumentSearcher {
private final Readable readable;
private final Searchable searchable;
public DocumentSearcher(Readable readable, Searchable searchable) {
this.readable = readable;
this.searchable = searchable;
}
public void findAndDisplay(String query) {
List<String> results = searchable.search(query);
results.forEach(System.out::println);
}
}
何时使用此技能
在以下情况下应用继承和组合:
- 设计具有共享行为的类层次结构
- 建模 IS-A 关系(继承)
- 建模 HAS-A 关系(组合)
- 创建可扩展框架
- 实现模板方法
- 构建灵活、可配置的系统
- 避免相关类之间的代码重复
- 支持运行时行为更改(组合)
- 实现策略模式
- 创建插件架构
- 使用依赖注入构建可测试代码
- 避免深层继承层次结构
- 支持行为的多种实现
- 创建可重用组件
- 实现接口隔离
最佳实践
- 优先选择组合而非继承以获得灵活性
- 使用继承处理真正的 IS-A 关系
- 保持继承层次浅(最多 2-3 层)
- 在适当时使基类抽象
- 使用接口/协议作为行为契约
- 偏好小型、聚焦的接口而非大型接口
- 使用依赖注入实现可组合设计
- 清晰记录模板方法模式
- 需要时正确重写方法并调用 super
- 使用 final/sealed 防止进一步继承
- 从小型、单一用途的组件组合行为
- 使用策略模式实现运行时行为更改
- 避免受保护字段,使用受保护方法
- 尽可能使组合对象不可变
- 独立测试每个组件
常见陷阱
- 创建深层继承层次结构
- 仅为了代码重用而使用继承
- 从具体类继承
- 破坏里氏替换原则
- 创建具有过多职责的上帝类
- 过度使用继承,而组合可能更好
- 使所有类继承自一个公共基类
- 使用受保护字段而非私有
- 在构造函数中忘记调用 super()
- 在组合中创建循环依赖
- 不考虑脆弱基类问题
- 使用实现继承而非接口继承
- 通过继承创建紧耦合
- 未在子类中正确重写 equals/hashCode
- 在基类中混合关注点
资源
- 设计模式:可复用面向对象软件的基础
- Effective Java by Joshua Bloch(优先选择组合而非继承)
- Head First 设计模式
- Python 多重继承:https://docs.python.org/3/tutorial/classes.html#multiple-inheritance
- C# 继承:https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance
- Java 继承教程:https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
- TypeScript 类:https://www.typescriptlang.org/docs/handbook/2/classes.html