oop-polymorphism

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OOP Polymorphism

面向对象编程(OOP)多态性

Master polymorphism to create flexible, extensible object-oriented systems. This skill focuses on understanding and applying polymorphic behavior through interfaces, abstract classes, and runtime type substitution.
掌握多态性,以创建灵活、可扩展的面向对象系统。本技能聚焦于通过接口、抽象类和运行时类型替换来理解和应用多态行为。

Understanding Polymorphism

理解多态性

Polymorphism allows objects of different types to be treated uniformly through a common interface. It enables writing code that works with abstractions rather than concrete implementations.
多态性允许不同类型的对象通过通用接口被统一处理。它能让你编写基于抽象而非具体实现的代码。

Interface-Based Polymorphism in Java

Java中基于接口的多态性

java
// Common interface for all payment methods
public interface PaymentMethod {
    PaymentResult process(BigDecimal amount);
    boolean isValid();
    String getDisplayName();
}

// Concrete implementations
public class CreditCard implements PaymentMethod {
    private final String cardNumber;
    private final String cardholderName;
    private final String expiryDate;
    private final String cvv;

    public CreditCard(String cardNumber, String cardholderName, String expiryDate, String cvv) {
        this.cardNumber = cardNumber;
        this.cardholderName = cardholderName;
        this.expiryDate = expiryDate;
        this.cvv = cvv;
    }

    @Override
    public PaymentResult process(BigDecimal amount) {
        if (!isValid()) {
            return PaymentResult.failed("Invalid credit card");
        }

        // Credit card processing logic
        String transactionId = UUID.randomUUID().toString();
        System.out.println("Processing $" + amount + " via credit card ending in " +
            cardNumber.substring(cardNumber.length() - 4));

        return PaymentResult.success(transactionId, amount);
    }

    @Override
    public boolean isValid() {
        return cardNumber != null &&
               cardNumber.length() == 16 &&
               !isExpired(expiryDate);
    }

    @Override
    public String getDisplayName() {
        return "Credit Card ending in " + cardNumber.substring(cardNumber.length() - 4);
    }

    private boolean isExpired(String expiryDate) {
        // Expiry date validation logic
        return false;
    }
}

public class PayPal implements PaymentMethod {
    private final String email;
    private final String password;

    public PayPal(String email, String password) {
        this.email = email;
        this.password = password;
    }

    @Override
    public PaymentResult process(BigDecimal amount) {
        if (!isValid()) {
            return PaymentResult.failed("Invalid PayPal credentials");
        }

        String transactionId = UUID.randomUUID().toString();
        System.out.println("Processing $" + amount + " via PayPal account " + email);

        return PaymentResult.success(transactionId, amount);
    }

    @Override
    public boolean isValid() {
        return email != null && email.contains("@") && password != null;
    }

    @Override
    public String getDisplayName() {
        return "PayPal (" + email + ")";
    }
}

public class BankTransfer implements PaymentMethod {
    private final String accountNumber;
    private final String routingNumber;
    private final String accountHolderName;

    public BankTransfer(String accountNumber, String routingNumber, String accountHolderName) {
        this.accountNumber = accountNumber;
        this.routingNumber = routingNumber;
        this.accountHolderName = accountHolderName;
    }

    @Override
    public PaymentResult process(BigDecimal amount) {
        if (!isValid()) {
            return PaymentResult.failed("Invalid bank account");
        }

        String transactionId = UUID.randomUUID().toString();
        System.out.println("Processing $" + amount + " via bank transfer from " + accountHolderName);

        return PaymentResult.success(transactionId, amount);
    }

    @Override
    public boolean isValid() {
        return accountNumber != null &&
               routingNumber != null &&
               accountNumber.length() > 0;
    }

    @Override
    public String getDisplayName() {
        return "Bank Account (" + accountHolderName + ")";
    }
}

// Polymorphic usage
public class PaymentProcessor {
    private final List<PaymentMethod> paymentMethods;

    public PaymentProcessor() {
        this.paymentMethods = new ArrayList<>();
    }

    public void addPaymentMethod(PaymentMethod method) {
        paymentMethods.add(method);
    }

    public PaymentResult processPayment(BigDecimal amount) {
        // Try each payment method until one succeeds
        for (PaymentMethod method : paymentMethods) {
            if (method.isValid()) {
                System.out.println("Attempting payment with " + method.getDisplayName());
                PaymentResult result = method.process(amount);

                if (result.isSuccess()) {
                    return result;
                }
            }
        }

        return PaymentResult.failed("No valid payment method available");
    }

    public List<String> getAvailablePaymentMethods() {
        return paymentMethods.stream()
            .filter(PaymentMethod::isValid)
            .map(PaymentMethod::getDisplayName)
            .collect(Collectors.toList());
    }
}

// Usage - polymorphism in action
PaymentProcessor processor = new PaymentProcessor();
processor.addPaymentMethod(new CreditCard("1234567890123456", "John Doe", "12/25", "123"));
processor.addPaymentMethod(new PayPal("john@example.com", "secret"));
processor.addPaymentMethod(new BankTransfer("9876543210", "123456789", "John Doe"));

PaymentResult result = processor.processPayment(new BigDecimal("99.99"));
java
// Common interface for all payment methods
public interface PaymentMethod {
    PaymentResult process(BigDecimal amount);
    boolean isValid();
    String getDisplayName();
}

// Concrete implementations
public class CreditCard implements PaymentMethod {
    private final String cardNumber;
    private final String cardholderName;
    private final String expiryDate;
    private final String cvv;

    public CreditCard(String cardNumber, String cardholderName, String expiryDate, String cvv) {
        this.cardNumber = cardNumber;
        this.cardholderName = cardholderName;
        this.expiryDate = expiryDate;
        this.cvv = cvv;
    }

    @Override
    public PaymentResult process(BigDecimal amount) {
        if (!isValid()) {
            return PaymentResult.failed("Invalid credit card");
        }

        // Credit card processing logic
        String transactionId = UUID.randomUUID().toString();
        System.out.println("Processing $" + amount + " via credit card ending in " +
            cardNumber.substring(cardNumber.length() - 4));

        return PaymentResult.success(transactionId, amount);
    }

    @Override
    public boolean isValid() {
        return cardNumber != null &&
               cardNumber.length() == 16 &&
               !isExpired(expiryDate);
    }

    @Override
    public String getDisplayName() {
        return "Credit Card ending in " + cardNumber.substring(cardNumber.length() - 4);
    }

    private boolean isExpired(String expiryDate) {
        // Expiry date validation logic
        return false;
    }
}

public class PayPal implements PaymentMethod {
    private final String email;
    private final String password;

    public PayPal(String email, String password) {
        this.email = email;
        this.password = password;
    }

    @Override
    public PaymentResult process(BigDecimal amount) {
        if (!isValid()) {
            return PaymentResult.failed("Invalid PayPal credentials");
        }

        String transactionId = UUID.randomUUID().toString();
        System.out.println("Processing $" + amount + " via PayPal account " + email);

        return PaymentResult.success(transactionId, amount);
    }

    @Override
    public boolean isValid() {
        return email != null && email.contains("@") && password != null;
    }

    @Override
    public String getDisplayName() {
        return "PayPal (" + email + ")";
    }
}

public class BankTransfer implements PaymentMethod {
    private final String accountNumber;
    private final String routingNumber;
    private final String accountHolderName;

    public BankTransfer(String accountNumber, String routingNumber, String accountHolderName) {
        this.accountNumber = accountNumber;
        this.routingNumber = routingNumber;
        this.accountHolderName = accountHolderName;
    }

    @Override
    public PaymentResult process(BigDecimal amount) {
        if (!isValid()) {
            return PaymentResult.failed("Invalid bank account");
        }

        String transactionId = UUID.randomUUID().toString();
        System.out.println("Processing $" + amount + " via bank transfer from " + accountHolderName);

        return PaymentResult.success(transactionId, amount);
    }

    @Override
    public boolean isValid() {
        return accountNumber != null &&
               routingNumber != null &&
               accountNumber.length() > 0;
    }

    @Override
    public String getDisplayName() {
        return "Bank Account (" + accountHolderName + ")";
    }
}

// Polymorphic usage
public class PaymentProcessor {
    private final List<PaymentMethod> paymentMethods;

    public PaymentProcessor() {
        this.paymentMethods = new ArrayList<>();
    }

    public void addPaymentMethod(PaymentMethod method) {
        paymentMethods.add(method);
    }

    public PaymentResult processPayment(BigDecimal amount) {
        // Try each payment method until one succeeds
        for (PaymentMethod method : paymentMethods) {
            if (method.isValid()) {
                System.out.println("Attempting payment with " + method.getDisplayName());
                PaymentResult result = method.process(amount);

                if (result.isSuccess()) {
                    return result;
                }
            }
        }

        return PaymentResult.failed("No valid payment method available");
    }

    public List<String> getAvailablePaymentMethods() {
        return paymentMethods.stream()
            .filter(PaymentMethod::isValid)
            .map(PaymentMethod::getDisplayName)
            .collect(Collectors.toList());
    }
}

// Usage - polymorphism in action
PaymentProcessor processor = new PaymentProcessor();
processor.addPaymentMethod(new CreditCard("1234567890123456", "John Doe", "12/25", "123"));
processor.addPaymentMethod(new PayPal("john@example.com", "secret"));
processor.addPaymentMethod(new BankTransfer("9876543210", "123456789", "John Doe"));

PaymentResult result = processor.processPayment(new BigDecimal("99.99"));

Protocol-Based Polymorphism in Python

Python中基于协议的多态性

python
from typing import Protocol, List, Optional
from abc import ABC, abstractmethod
from dataclasses import dataclass
import json
python
from typing import Protocol, List, Optional
from abc import ABC, abstractmethod
from dataclasses import dataclass
import json

Protocol defines the interface (structural typing)

Protocol defines the interface (structural typing)

class Serializable(Protocol): """Protocol for objects that can be serialized."""
def to_dict(self) -> dict:
    """Convert to dictionary."""
    ...

def to_json(self) -> str:
    """Convert to JSON string."""
    ...
class Serializable(Protocol): """Protocol for objects that can be serialized."""
def to_dict(self) -> dict:
    """Convert to dictionary."""
    ...

def to_json(self) -> str:
    """Convert to JSON string."""
    ...

Another protocol

Another protocol

class Identifiable(Protocol): """Protocol for objects with an ID."""
@property
def id(self) -> str:
    """Get unique identifier."""
    ...
class Identifiable(Protocol): """Protocol for objects with an ID."""
@property
def id(self) -> str:
    """Get unique identifier."""
    ...

Concrete implementations

Concrete implementations

@dataclass class User: """User implementation with both protocols."""
_id: str
username: str
email: str
age: int

@property
def id(self) -> str:
    return self._id

def to_dict(self) -> dict:
    return {
        'id': self._id,
        'username': self.username,
        'email': self.email,
        'age': self.age
    }

def to_json(self) -> str:
    return json.dumps(self.to_dict())
@dataclass class Product: """Product implementation with both protocols."""
_id: str
name: str
price: float
category: str

@property
def id(self) -> str:
    return self._id

def to_dict(self) -> dict:
    return {
        'id': self._id,
        'name': self.name,
        'price': self.price,
        'category': self.category
    }

def to_json(self) -> str:
    return json.dumps(self.to_dict())
@dataclass class Order: """Order implementation."""
_id: str
user_id: str
items: List[str]
total: float

@property
def id(self) -> str:
    return self._id

def to_dict(self) -> dict:
    return {
        'id': self._id,
        'user_id': self.user_id,
        'items': self.items,
        'total': self.total
    }

def to_json(self) -> str:
    return json.dumps(self.to_dict())
@dataclass class User: """User implementation with both protocols."""
_id: str
username: str
email: str
age: int

@property
def id(self) -> str:
    return self._id

def to_dict(self) -> dict:
    return {
        'id': self._id,
        'username': self.username,
        'email': self.email,
        'age': self.age
    }

def to_json(self) -> str:
    return json.dumps(self.to_dict())
@dataclass class Product: """Product implementation with both protocols."""
_id: str
name: str
price: float
category: str

@property
def id(self) -> str:
    return self._id

def to_dict(self) -> dict:
    return {
        'id': self._id,
        'name': self.name,
        'price': self.price,
        'category': self.category
    }

def to_json(self) -> str:
    return json.dumps(self.to_dict())
@dataclass class Order: """Order implementation."""
_id: str
user_id: str
items: List[str]
total: float

@property
def id(self) -> str:
    return self._id

def to_dict(self) -> dict:
    return {
        'id': self._id,
        'user_id': self.user_id,
        'items': self.items,
        'total': self.total
    }

def to_json(self) -> str:
    return json.dumps(self.to_dict())

Polymorphic functions using protocols

Polymorphic functions using protocols

def save_to_file(obj: Serializable, filename: str) -> None: """Save any serializable object to file.""" with open(filename, 'w') as f: f.write(obj.to_json())
def get_id(obj: Identifiable) -> str: """Get ID from any identifiable object.""" return obj.id
def serialize_batch(objects: List[Serializable]) -> str: """Serialize multiple objects.""" return json.dumps([obj.to_dict() for obj in objects])
def save_to_file(obj: Serializable, filename: str) -> None: """Save any serializable object to file.""" with open(filename, 'w') as f: f.write(obj.to_json())
def get_id(obj: Identifiable) -> str: """Get ID from any identifiable object.""" return obj.id
def serialize_batch(objects: List[Serializable]) -> str: """Serialize multiple objects.""" return json.dumps([obj.to_dict() for obj in objects])

Works with any object implementing the protocols

Works with any object implementing the protocols

user = User("u1", "alice", "alice@example.com", 30) product = Product("p1", "Laptop", 999.99, "Electronics") order = Order("o1", "u1", ["p1"], 999.99)
save_to_file(user, "user.json") save_to_file(product, "product.json")
all_objects = [user, product, order] batch_json = serialize_batch(all_objects)
undefined
user = User("u1", "alice", "alice@example.com", 30) product = Product("p1", "Laptop", 999.99, "Electronics") order = Order("o1", "u1", ["p1"], 999.99)
save_to_file(user, "user.json") save_to_file(product, "product.json")
all_objects = [user, product, order] batch_json = serialize_batch(all_objects)
undefined

Abstract Base Classes in Python

Python中的抽象基类

python
from abc import ABC, abstractmethod
from typing import List, Dict, Any
from datetime import datetime
python
from abc import ABC, abstractmethod
from typing import List, Dict, Any
from datetime import datetime

Abstract base class defining contract

Abstract base class defining contract

class DataStore(ABC): """Abstract base class for data storage."""
@abstractmethod
def connect(self) -> None:
    """Establish connection to data store."""
    pass

@abstractmethod
def disconnect(self) -> None:
    """Close connection to data store."""
    pass

@abstractmethod
def save(self, key: str, value: Any) -> bool:
    """Save value with given key."""
    pass

@abstractmethod
def load(self, key: str) -> Optional[Any]:
    """Load value for given key."""
    pass

@abstractmethod
def delete(self, key: str) -> bool:
    """Delete value for given key."""
    pass

@abstractmethod
def list_keys(self) -> List[str]:
    """List all keys in store."""
    pass

# Concrete method with default implementation
def exists(self, key: str) -> bool:
    """Check if key exists."""
    return self.load(key) is not None

def save_batch(self, items: Dict[str, Any]) -> int:
    """Save multiple items."""
    count = 0
    for key, value in items.items():
        if self.save(key, value):
            count += 1
    return count
class DataStore(ABC): """Abstract base class for data storage."""
@abstractmethod
def connect(self) -> None:
    """Establish connection to data store."""
    pass

@abstractmethod
def disconnect(self) -> None:
    """Close connection to data store."""
    pass

@abstractmethod
def save(self, key: str, value: Any) -> bool:
    """Save value with given key."""
    pass

@abstractmethod
def load(self, key: str) -> Optional[Any]:
    """Load value for given key."""
    pass

@abstractmethod
def delete(self, key: str) -> bool:
    """Delete value for given key."""
    pass

@abstractmethod
def list_keys(self) -> List[str]:
    """List all keys in store."""
    pass

# Concrete method with default implementation
def exists(self, key: str) -> bool:
    """Check if key exists."""
    return self.load(key) is not None

def save_batch(self, items: Dict[str, Any]) -> int:
    """Save multiple items."""
    count = 0
    for key, value in items.items():
        if self.save(key, value):
            count += 1
    return count

Concrete implementation - In-memory store

Concrete implementation - In-memory store

class MemoryStore(DataStore): """In-memory data store implementation."""
def __init__(self):
    self._data: Dict[str, Any] = {}
    self._connected = False

def connect(self) -> None:
    self._connected = True
    print("Memory store connected")

def disconnect(self) -> None:
    self._connected = False
    print("Memory store disconnected")

def save(self, key: str, value: Any) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")
    self._data[key] = value
    return True

def load(self, key: str) -> Optional[Any]:
    if not self._connected:
        raise RuntimeError("Not connected")
    return self._data.get(key)

def delete(self, key: str) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")
    if key in self._data:
        del self._data[key]
        return True
    return False

def list_keys(self) -> List[str]:
    if not self._connected:
        raise RuntimeError("Not connected")
    return list(self._data.keys())
class MemoryStore(DataStore): """In-memory data store implementation."""
def __init__(self):
    self._data: Dict[str, Any] = {}
    self._connected = False

def connect(self) -> None:
    self._connected = True
    print("Memory store connected")

def disconnect(self) -> None:
    self._connected = False
    print("Memory store disconnected")

def save(self, key: str, value: Any) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")
    self._data[key] = value
    return True

def load(self, key: str) -> Optional[Any]:
    if not self._connected:
        raise RuntimeError("Not connected")
    return self._data.get(key)

def delete(self, key: str) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")
    if key in self._data:
        del self._data[key]
        return True
    return False

def list_keys(self) -> List[str]:
    if not self._connected:
        raise RuntimeError("Not connected")
    return list(self._data.keys())

Concrete implementation - File-based store

Concrete implementation - File-based store

class FileStore(DataStore): """File-based data store implementation."""
def __init__(self, directory: str):
    self._directory = directory
    self._connected = False

def connect(self) -> None:
    import os
    os.makedirs(self._directory, exist_ok=True)
    self._connected = True
    print(f"File store connected: {self._directory}")

def disconnect(self) -> None:
    self._connected = False
    print("File store disconnected")

def save(self, key: str, value: Any) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")

    import json
    filepath = os.path.join(self._directory, f"{key}.json")
    try:
        with open(filepath, 'w') as f:
            json.dump(value, f)
        return True
    except Exception as e:
        print(f"Error saving {key}: {e}")
        return False

def load(self, key: str) -> Optional[Any]:
    if not self._connected:
        raise RuntimeError("Not connected")

    import json
    filepath = os.path.join(self._directory, f"{key}.json")
    try:
        with open(filepath, 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return None
    except Exception as e:
        print(f"Error loading {key}: {e}")
        return None

def delete(self, key: str) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")

    import os
    filepath = os.path.join(self._directory, f"{key}.json")
    try:
        os.remove(filepath)
        return True
    except FileNotFoundError:
        return False

def list_keys(self) -> List[str]:
    if not self._connected:
        raise RuntimeError("Not connected")

    import os
    return [
        f[:-5] for f in os.listdir(self._directory)
        if f.endswith('.json')
    ]
class FileStore(DataStore): """File-based data store implementation."""
def __init__(self, directory: str):
    self._directory = directory
    self._connected = False

def connect(self) -> None:
    import os
    os.makedirs(self._directory, exist_ok=True)
    self._connected = True
    print(f"File store connected: {self._directory}")

def disconnect(self) -> None:
    self._connected = False
    print("File store disconnected")

def save(self, key: str, value: Any) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")

    import json
    filepath = os.path.join(self._directory, f"{key}.json")
    try:
        with open(filepath, 'w') as f:
            json.dump(value, f)
        return True
    except Exception as e:
        print(f"Error saving {key}: {e}")
        return False

def load(self, key: str) -> Optional[Any]:
    if not self._connected:
        raise RuntimeError("Not connected")

    import json
    filepath = os.path.join(self._directory, f"{key}.json")
    try:
        with open(filepath, 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return None
    except Exception as e:
        print(f"Error loading {key}: {e}")
        return None

def delete(self, key: str) -> bool:
    if not self._connected:
        raise RuntimeError("Not connected")

    import os
    filepath = os.path.join(self._directory, f"{key}.json")
    try:
        os.remove(filepath)
        return True
    except FileNotFoundError:
        return False

def list_keys(self) -> List[str]:
    if not self._connected:
        raise RuntimeError("Not connected")

    import os
    return [
        f[:-5] for f in os.listdir(self._directory)
        if f.endswith('.json')
    ]

Polymorphic usage

Polymorphic usage

class DataManager: """Manager that works with any DataStore."""
def __init__(self, store: DataStore):
    self._store = store

def __enter__(self):
    self._store.connect()
    return self

def __exit__(self, exc_type, exc_val, exc_tb):
    self._store.disconnect()

def backup(self, source_store: DataStore) -> int:
    """Backup from another store."""
    count = 0
    for key in source_store.list_keys():
        value = source_store.load(key)
        if value is not None and self._store.save(key, value):
            count += 1
    return count

def migrate(self, target_store: DataStore) -> int:
    """Migrate data to another store."""
    count = 0
    for key in self._store.list_keys():
        value = self._store.load(key)
        if value is not None and target_store.save(key, value):
            count += 1
    return count
class DataManager: """Manager that works with any DataStore."""
def __init__(self, store: DataStore):
    self._store = store

def __enter__(self):
    self._store.connect()
    return self

def __exit__(self, exc_type, exc_val, exc_tb):
    self._store.disconnect()

def backup(self, source_store: DataStore) -> int:
    """Backup from another store."""
    count = 0
    for key in source_store.list_keys():
        value = source_store.load(key)
        if value is not None and self._store.save(key, value):
            count += 1
    return count

def migrate(self, target_store: DataStore) -> int:
    """Migrate data to another store."""
    count = 0
    for key in self._store.list_keys():
        value = self._store.load(key)
        if value is not None and target_store.save(key, value):
            count += 1
    return count

Usage with different implementations

Usage with different implementations

with DataManager(MemoryStore()) as manager: manager._store.save("user:1", {"name": "Alice", "age": 30})
with DataManager(FileStore("./data")) as manager: manager._store.save("user:2", {"name": "Bob", "age": 25})
undefined
with DataManager(MemoryStore()) as manager: manager._store.save("user:1", {"name": "Alice", "age": 30})
with DataManager(FileStore("./data")) as manager: manager._store.save("user:2", {"name": "Bob", "age": 25})
undefined

TypeScript Polymorphism

TypeScript多态性

typescript
// Interface-based polymorphism
interface Logger {
  log(message: string, level: string): void;
  flush(): void;
}

interface Formatter {
  format(message: string, level: string): string;
}

// Concrete implementations
class ConsoleLogger implements Logger {
  private formatter: Formatter;

  constructor(formatter: Formatter) {
    this.formatter = formatter;
  }

  log(message: string, level: string): void {
    const formatted = this.formatter.format(message, level);
    console.log(formatted);
  }

  flush(): void {
    // Console logs immediately, nothing to flush
  }
}

class FileLogger implements Logger {
  private formatter: Formatter;
  private buffer: string[] = [];
  private readonly filename: string;

  constructor(filename: string, formatter: Formatter) {
    this.filename = filename;
    this.formatter = formatter;
  }

  log(message: string, level: string): void {
    const formatted = this.formatter.format(message, level);
    this.buffer.push(formatted);

    if (this.buffer.length >= 10) {
      this.flush();
    }
  }

  flush(): void {
    if (this.buffer.length === 0) return;

    // Write to file (simplified)
    const content = this.buffer.join('\n');
    console.log(`Writing to ${this.filename}:`, content);
    this.buffer = [];
  }
}

class JsonFormatter implements Formatter {
  format(message: string, level: string): string {
    return JSON.stringify({
      message,
      level,
      timestamp: new Date().toISOString()
    });
  }
}

class TextFormatter implements Formatter {
  format(message: string, level: string): string {
    const timestamp = new Date().toISOString();
    return `[${timestamp}] [${level}] ${message}`;
  }
}

// Composite logger using polymorphism
class MultiLogger implements Logger {
  private loggers: Logger[] = [];

  addLogger(logger: Logger): void {
    this.loggers.push(logger);
  }

  log(message: string, level: string): void {
    for (const logger of this.loggers) {
      logger.log(message, level);
    }
  }

  flush(): void {
    for (const logger of this.loggers) {
      logger.flush();
    }
  }
}

// Application using polymorphism
class Application {
  private logger: Logger;

  constructor(logger: Logger) {
    this.logger = logger;
  }

  run(): void {
    this.logger.log("Application started", "INFO");
    this.processData();
    this.logger.log("Application finished", "INFO");
    this.logger.flush();
  }

  private processData(): void {
    this.logger.log("Processing data", "DEBUG");
    // Processing logic
  }
}

// Usage - can swap implementations
const jsonFormatter = new JsonFormatter();
const textFormatter = new TextFormatter();

const consoleLogger = new ConsoleLogger(textFormatter);
const fileLogger = new FileLogger("app.log", jsonFormatter);

const multiLogger = new MultiLogger();
multiLogger.addLogger(consoleLogger);
multiLogger.addLogger(fileLogger);

// Application works with any Logger implementation
const app = new Application(multiLogger);
app.run();
typescript
// Interface-based polymorphism
interface Logger {
  log(message: string, level: string): void;
  flush(): void;
}

interface Formatter {
  format(message: string, level: string): string;
}

// Concrete implementations
class ConsoleLogger implements Logger {
  private formatter: Formatter;

  constructor(formatter: Formatter) {
    this.formatter = formatter;
  }

  log(message: string, level: string): void {
    const formatted = this.formatter.format(message, level);
    console.log(formatted);
  }

  flush(): void {
    // Console logs immediately, nothing to flush
  }
}

class FileLogger implements Logger {
  private formatter: Formatter;
  private buffer: string[] = [];
  private readonly filename: string;

  constructor(filename: string, formatter: Formatter) {
    this.filename = filename;
    this.formatter = formatter;
  }

  log(message: string, level: string): void {
    const formatted = this.formatter.format(message, level);
    this.buffer.push(formatted);

    if (this.buffer.length >= 10) {
      this.flush();
    }
  }

  flush(): void {
    if (this.buffer.length === 0) return;

    // Write to file (simplified)
    const content = this.buffer.join('\n');
    console.log(`Writing to ${this.filename}:`, content);
    this.buffer = [];
  }
}

class JsonFormatter implements Formatter {
  format(message: string, level: string): string {
    return JSON.stringify({
      message,
      level,
      timestamp: new Date().toISOString()
    });
  }
}

class TextFormatter implements Formatter {
  format(message: string, level: string): string {
    const timestamp = new Date().toISOString();
    return `[${timestamp}] [${level}] ${message}`;
  }
}

// Composite logger using polymorphism
class MultiLogger implements Logger {
  private loggers: Logger[] = [];

  addLogger(logger: Logger): void {
    this.loggers.push(logger);
  }

  log(message: string, level: string): void {
    for (const logger of this.loggers) {
      logger.log(message, level);
    }
  }

  flush(): void {
    for (const logger of this.loggers) {
      logger.flush();
    }
  }
}

// Application using polymorphism
class Application {
  private logger: Logger;

  constructor(logger: Logger) {
    this.logger = logger;
  }

  run(): void {
    this.logger.log("Application started", "INFO");
    this.processData();
    this.logger.log("Application finished", "INFO");
    this.logger.flush();
  }

  private processData(): void {
    this.logger.log("Processing data", "DEBUG");
    // Processing logic
  }
}

// Usage - can swap implementations
const jsonFormatter = new JsonFormatter();
const textFormatter = new TextFormatter();

const consoleLogger = new ConsoleLogger(textFormatter);
const fileLogger = new FileLogger("app.log", jsonFormatter);

const multiLogger = new MultiLogger();
multiLogger.addLogger(consoleLogger);
multiLogger.addLogger(fileLogger);

// Application works with any Logger implementation
const app = new Application(multiLogger);
app.run();

C# Polymorphism with Interfaces

C#中基于接口的多态性

csharp
// Interface for notification services
public interface INotificationService
{
    Task SendAsync(string recipient, string subject, string body);
    bool IsAvailable();
    string GetServiceName();
}

// Concrete implementations
public class EmailNotificationService : INotificationService
{
    private readonly string _smtpServer;
    private readonly int _port;
    private readonly string _username;
    private readonly string _password;

    public EmailNotificationService(string smtpServer, int port, string username, string password)
    {
        _smtpServer = smtpServer;
        _port = port;
        _username = username;
        _password = password;
    }

    public async Task SendAsync(string recipient, string subject, string body)
    {
        if (!IsAvailable())
            throw new InvalidOperationException("Email service not available");

        Console.WriteLine($"Sending email to {recipient}");
        Console.WriteLine($"Subject: {subject}");
        Console.WriteLine($"Body: {body}");

        // Simulate sending email
        await Task.Delay(100);
    }

    public bool IsAvailable()
    {
        return !string.IsNullOrEmpty(_smtpServer);
    }

    public string GetServiceName()
    {
        return "Email";
    }
}

public class SmsNotificationService : INotificationService
{
    private readonly string _apiKey;
    private readonly string _phoneNumber;

    public SmsNotificationService(string apiKey, string phoneNumber)
    {
        _apiKey = apiKey;
        _phoneNumber = phoneNumber;
    }

    public async Task SendAsync(string recipient, string subject, string body)
    {
        if (!IsAvailable())
            throw new InvalidOperationException("SMS service not available");

        Console.WriteLine($"Sending SMS to {recipient}");
        Console.WriteLine($"Message: {subject} - {body}");

        await Task.Delay(50);
    }

    public bool IsAvailable()
    {
        return !string.IsNullOrEmpty(_apiKey);
    }

    public string GetServiceName()
    {
        return "SMS";
    }
}

public class PushNotificationService : INotificationService
{
    private readonly string _appId;
    private readonly string _apiKey;

    public PushNotificationService(string appId, string apiKey)
    {
        _appId = appId;
        _apiKey = apiKey;
    }

    public async Task SendAsync(string recipient, string subject, string body)
    {
        if (!IsAvailable())
            throw new InvalidOperationException("Push notification service not available");

        Console.WriteLine($"Sending push notification to {recipient}");
        Console.WriteLine($"Title: {subject}");
        Console.WriteLine($"Body: {body}");

        await Task.Delay(30);
    }

    public bool IsAvailable()
    {
        return !string.IsNullOrEmpty(_appId) && !string.IsNullOrEmpty(_apiKey);
    }

    public string GetServiceName()
    {
        return "Push Notification";
    }
}

// Polymorphic notification manager
public class NotificationManager
{
    private readonly List<INotificationService> _services;

    public NotificationManager()
    {
        _services = new List<INotificationService>();
    }

    public void RegisterService(INotificationService service)
    {
        _services.Add(service);
    }

    public async Task NotifyAsync(string recipient, string subject, string body)
    {
        var availableServices = _services.Where(s => s.IsAvailable()).ToList();

        if (!availableServices.Any())
        {
            throw new InvalidOperationException("No notification services available");
        }

        Console.WriteLine($"Sending via {availableServices.Count} service(s)");

        var tasks = availableServices.Select(service =>
            NotifyWithServiceAsync(service, recipient, subject, body)
        );

        await Task.WhenAll(tasks);
    }

    private async Task NotifyWithServiceAsync(
        INotificationService service,
        string recipient,
        string subject,
        string body)
    {
        try
        {
            await service.SendAsync(recipient, subject, body);
            Console.WriteLine($"{service.GetServiceName()} notification sent successfully");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{service.GetServiceName()} notification failed: {ex.Message}");
        }
    }

    public List<string> GetAvailableServices()
    {
        return _services
            .Where(s => s.IsAvailable())
            .Select(s => s.GetServiceName())
            .ToList();
    }
}

// Usage
var manager = new NotificationManager();
manager.RegisterService(new EmailNotificationService("smtp.example.com", 587, "user", "pass"));
manager.RegisterService(new SmsNotificationService("api-key", "+1234567890"));
manager.RegisterService(new PushNotificationService("app-id", "api-key"));

await manager.NotifyAsync("user@example.com", "Welcome", "Welcome to our service!");
csharp
// Interface for notification services
public interface INotificationService
{
    Task SendAsync(string recipient, string subject, string body);
    bool IsAvailable();
    string GetServiceName();
}

// Concrete implementations
public class EmailNotificationService : INotificationService
{
    private readonly string _smtpServer;
    private readonly int _port;
    private readonly string _username;
    private readonly string _password;

    public EmailNotificationService(string smtpServer, int port, string username, string password)
    {
        _smtpServer = smtpServer;
        _port = port;
        _username = username;
        _password = password;
    }

    public async Task SendAsync(string recipient, string subject, string body)
    {
        if (!IsAvailable())
            throw new InvalidOperationException("Email service not available");

        Console.WriteLine($"Sending email to {recipient}");
        Console.WriteLine($"Subject: {subject}");
        Console.WriteLine($"Body: {body}");

        // Simulate sending email
        await Task.Delay(100);
    }

    public bool IsAvailable()
    {
        return !string.IsNullOrEmpty(_smtpServer);
    }

    public string GetServiceName()
    {
        return "Email";
    }
}

public class SmsNotificationService : INotificationService
{
    private readonly string _apiKey;
    private readonly string _phoneNumber;

    public SmsNotificationService(string apiKey, string phoneNumber)
    {
        _apiKey = apiKey;
        _phoneNumber = phoneNumber;
    }

    public async Task SendAsync(string recipient, string subject, string body)
    {
        if (!IsAvailable())
            throw new InvalidOperationException("SMS service not available");

        Console.WriteLine($"Sending SMS to {recipient}");
        Console.WriteLine($"Message: {subject} - {body}");

        await Task.Delay(50);
    }

    public bool IsAvailable()
    {
        return !string.IsNullOrEmpty(_apiKey);
    }

    public string GetServiceName()
    {
        return "SMS";
    }
}

public class PushNotificationService : INotificationService
{
    private readonly string _appId;
    private readonly string _apiKey;

    public PushNotificationService(string appId, string apiKey)
    {
        _appId = appId;
        _apiKey = apiKey;
    }

    public async Task SendAsync(string recipient, string subject, string body)
    {
        if (!IsAvailable())
            throw new InvalidOperationException("Push notification service not available");

        Console.WriteLine($"Sending push notification to {recipient}");
        Console.WriteLine($"Title: {subject}");
        Console.WriteLine($"Body: {body}");

        await Task.Delay(30);
    }

    public bool IsAvailable()
    {
        return !string.IsNullOrEmpty(_appId) && !string.IsNullOrEmpty(_apiKey);
    }

    public string GetServiceName()
    {
        return "Push Notification";
    }
}

// Polymorphic notification manager
public class NotificationManager
{
    private readonly List<INotificationService> _services;

    public NotificationManager()
    {
        _services = new List<INotificationService>();
    }

    public void RegisterService(INotificationService service)
    {
        _services.Add(service);
    }

    public async Task NotifyAsync(string recipient, string subject, string body)
    {
        var availableServices = _services.Where(s => s.IsAvailable()).ToList();

        if (!availableServices.Any())
        {
            throw new InvalidOperationException("No notification services available");
        }

        Console.WriteLine($"Sending via {availableServices.Count} service(s)");

        var tasks = availableServices.Select(service =>
            NotifyWithServiceAsync(service, recipient, subject, body)
        );

        await Task.WhenAll(tasks);
    }

    private async Task NotifyWithServiceAsync(
        INotificationService service,
        string recipient,
        string subject,
        string body)
    {
        try
        {
            await service.SendAsync(recipient, subject, body);
            Console.WriteLine($"{service.GetServiceName()} notification sent successfully");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{service.GetServiceName()} notification failed: {ex.Message}");
        }
    }

    public List<string> GetAvailableServices()
    {
        return _services
            .Where(s => s.IsAvailable())
            .Select(s => s.GetServiceName())
            .ToList();
    }
}

// Usage
var manager = new NotificationManager();
manager.RegisterService(new EmailNotificationService("smtp.example.com", 587, "user", "pass"));
manager.RegisterService(new SmsNotificationService("api-key", "+1234567890"));
manager.RegisterService(new PushNotificationService("app-id", "api-key"));

await manager.NotifyAsync("user@example.com", "Welcome", "Welcome to our service!");

Method Overloading

方法重载

Overloading in Java

Java中的方法重载

java
public class Calculator {
    // Method overloading - same name, different parameters

    // Add two integers
    public int add(int a, int b) {
        return a + b;
    }

    // Add three integers
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // Add two doubles
    public double add(double a, double b) {
        return a + b;
    }

    // Add array of integers
    public int add(int[] numbers) {
        int sum = 0;
        for (int num : numbers) {
            sum += num;
        }
        return sum;
    }

    // Add with different type combinations
    public double add(int a, double b) {
        return a + b;
    }

    public double add(double a, int b) {
        return a + b;
    }
}

// String formatting with overloading
public class Formatter {
    public String format(String text) {
        return text.trim();
    }

    public String format(String text, boolean uppercase) {
        String trimmed = format(text);
        return uppercase ? trimmed.toUpperCase() : trimmed.toLowerCase();
    }

    public String format(String text, int maxLength) {
        String trimmed = format(text);
        return trimmed.length() > maxLength
            ? trimmed.substring(0, maxLength) + "..."
            : trimmed;
    }

    public String format(String text, boolean uppercase, int maxLength) {
        String formatted = format(text, uppercase);
        return format(formatted, maxLength);
    }
}
java
public class Calculator {
    // Method overloading - same name, different parameters

    // Add two integers
    public int add(int a, int b) {
        return a + b;
    }

    // Add three integers
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // Add two doubles
    public double add(double a, double b) {
        return a + b;
    }

    // Add array of integers
    public int add(int[] numbers) {
        int sum = 0;
        for (int num : numbers) {
            sum += num;
        }
        return sum;
    }

    // Add with different type combinations
    public double add(int a, double b) {
        return a + b;
    }

    public double add(double a, int b) {
        return a + b;
    }
}

// String formatting with overloading
public class Formatter {
    public String format(String text) {
        return text.trim();
    }

    public String format(String text, boolean uppercase) {
        String trimmed = format(text);
        return uppercase ? trimmed.toUpperCase() : trimmed.toLowerCase();
    }

    public String format(String text, int maxLength) {
        String trimmed = format(text);
        return trimmed.length() > maxLength
            ? trimmed.substring(0, maxLength) + "..."
            : trimmed;
    }

    public String format(String text, boolean uppercase, int maxLength) {
        String formatted = format(text, uppercase);
        return format(formatted, maxLength);
    }
}

Overloading in C

C#中的方法重载

csharp
public class DocumentProcessor
{
    // Process string content
    public ProcessResult Process(string content)
    {
        return new ProcessResult
        {
            Type = "text",
            Length = content.Length,
            ProcessedContent = content.Trim()
        };
    }

    // Process byte array (binary content)
    public ProcessResult Process(byte[] content)
    {
        return new ProcessResult
        {
            Type = "binary",
            Length = content.Length,
            ProcessedContent = Convert.ToBase64String(content)
        };
    }

    // Process with options
    public ProcessResult Process(string content, ProcessOptions options)
    {
        var result = Process(content);

        if (options.RemoveWhitespace)
        {
            result.ProcessedContent = Regex.Replace(
                result.ProcessedContent.ToString(),
                @"\s+",
                " "
            );
        }

        if (options.MaxLength > 0)
        {
            var text = result.ProcessedContent.ToString();
            result.ProcessedContent = text.Length > options.MaxLength
                ? text.Substring(0, options.MaxLength)
                : text;
        }

        return result;
    }

    // Process file
    public async Task<ProcessResult> ProcessAsync(FileInfo file)
    {
        var content = await File.ReadAllTextAsync(file.FullName);
        return Process(content);
    }

    // Process stream
    public async Task<ProcessResult> ProcessAsync(Stream stream)
    {
        using var reader = new StreamReader(stream);
        var content = await reader.ReadToEndAsync();
        return Process(content);
    }
}
csharp
public class DocumentProcessor
{
    // Process string content
    public ProcessResult Process(string content)
    {
        return new ProcessResult
        {
            Type = "text",
            Length = content.Length,
            ProcessedContent = content.Trim()
        };
    }

    // Process byte array (binary content)
    public ProcessResult Process(byte[] content)
    {
        return new ProcessResult
        {
            Type = "binary",
            Length = content.Length,
            ProcessedContent = Convert.ToBase64String(content)
        };
    }

    // Process with options
    public ProcessResult Process(string content, ProcessOptions options)
    {
        var result = Process(content);

        if (options.RemoveWhitespace)
        {
            result.ProcessedContent = Regex.Replace(
                result.ProcessedContent.ToString(),
                @"\s+",
                " "
            );
        }

        if (options.MaxLength > 0)
        {
            var text = result.ProcessedContent.ToString();
            result.ProcessedContent = text.Length > options.MaxLength
                ? text.Substring(0, options.MaxLength)
                : text;
        }

        return result;
    }

    // Process file
    public async Task<ProcessResult> ProcessAsync(FileInfo file)
    {
        var content = await File.ReadAllTextAsync(file.FullName);
        return Process(content);
    }

    // Process stream
    public async Task<ProcessResult> ProcessAsync(Stream stream)
    {
        using var reader = new StreamReader(stream);
        var content = await reader.ReadToEndAsync();
        return Process(content);
    }
}

Operator Overloading

运算符重载

C# Operator Overloading

C#运算符重载

csharp
public struct Vector3D
{
    public double X { get; }
    public double Y { get; }
    public double Z { get; }

    public Vector3D(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    // Binary operator overloading
    public static Vector3D operator +(Vector3D a, Vector3D b)
    {
        return new Vector3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
    }

    public static Vector3D operator -(Vector3D a, Vector3D b)
    {
        return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
    }

    public static Vector3D operator *(Vector3D v, double scalar)
    {
        return new Vector3D(v.X * scalar, v.Y * scalar, v.Z * scalar);
    }

    public static Vector3D operator *(double scalar, Vector3D v)
    {
        return v * scalar;
    }

    public static Vector3D operator /(Vector3D v, double scalar)
    {
        if (scalar == 0)
            throw new DivideByZeroException();
        return new Vector3D(v.X / scalar, v.Y / scalar, v.Z / scalar);
    }

    // Unary operator overloading
    public static Vector3D operator -(Vector3D v)
    {
        return new Vector3D(-v.X, -v.Y, -v.Z);
    }

    // Comparison operators
    public static bool operator ==(Vector3D a, Vector3D b)
    {
        return a.X == b.X && a.Y == b.Y && a.Z == b.Z;
    }

    public static bool operator !=(Vector3D a, Vector3D b)
    {
        return !(a == b);
    }

    // Override Object methods
    public override bool Equals(object obj)
    {
        return obj is Vector3D vector && this == vector;
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(X, Y, Z);
    }

    public override string ToString()
    {
        return $"({X}, {Y}, {Z})";
    }

    // Additional vector operations
    public double Magnitude()
    {
        return Math.Sqrt(X * X + Y * Y + Z * Z);
    }

    public Vector3D Normalize()
    {
        double mag = Magnitude();
        return mag > 0 ? this / mag : this;
    }

    public double Dot(Vector3D other)
    {
        return X * other.X + Y * other.Y + Z * other.Z;
    }

    public Vector3D Cross(Vector3D other)
    {
        return new Vector3D(
            Y * other.Z - Z * other.Y,
            Z * other.X - X * other.Z,
            X * other.Y - Y * other.X
        );
    }
}

// Usage
var v1 = new Vector3D(1, 2, 3);
var v2 = new Vector3D(4, 5, 6);
var v3 = v1 + v2;  // (5, 7, 9)
var v4 = v1 * 2;   // (2, 4, 6)
var v5 = -v1;      // (-1, -2, -3)
csharp
public struct Vector3D
{
    public double X { get; }
    public double Y { get; }
    public double Z { get; }

    public Vector3D(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    // Binary operator overloading
    public static Vector3D operator +(Vector3D a, Vector3D b)
    {
        return new Vector3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
    }

    public static Vector3D operator -(Vector3D a, Vector3D b)
    {
        return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
    }

    public static Vector3D operator *(Vector3D v, double scalar)
    {
        return new Vector3D(v.X * scalar, v.Y * scalar, v.Z * scalar);
    }

    public static Vector3D operator *(double scalar, Vector3D v)
    {
        return v * scalar;
    }

    public static Vector3D operator /(Vector3D v, double scalar)
    {
        if (scalar == 0)
            throw new DivideByZeroException();
        return new Vector3D(v.X / scalar, v.Y / scalar, v.Z / scalar);
    }

    // Unary operator overloading
    public static Vector3D operator -(Vector3D v)
    {
        return new Vector3D(-v.X, -v.Y, -v.Z);
    }

    // Comparison operators
    public static bool operator ==(Vector3D a, Vector3D b)
    {
        return a.X == b.X && a.Y == b.Y && a.Z == b.Z;
    }

    public static bool operator !=(Vector3D a, Vector3D b)
    {
        return !(a == b);
    }

    // Override Object methods
    public override bool Equals(object obj)
    {
        return obj is Vector3D vector && this == vector;
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(X, Y, Z);
    }

    public override string ToString()
    {
        return $"({X}, {Y}, {Z})";
    }

    // Additional vector operations
    public double Magnitude()
    {
        return Math.Sqrt(X * X + Y * Y + Z * Z);
    }

    public Vector3D Normalize()
    {
        double mag = Magnitude();
        return mag > 0 ? this / mag : this;
    }

    public double Dot(Vector3D other)
    {
        return X * other.X + Y * other.Y + Z * other.Z;
    }

    public Vector3D Cross(Vector3D other)
    {
        return new Vector3D(
            Y * other.Z - Z * other.Y,
            Z * other.X - X * other.Z,
            X * other.Y - Y * other.X
        );
    }
}

// Usage
var v1 = new Vector3D(1, 2, 3);
var v2 = new Vector3D(4, 5, 6);
var v3 = v1 + v2;  // (5, 7, 9)
var v4 = v1 * 2;   // (2, 4, 6)
var v5 = -v1;      // (-1, -2, -3)

Python Magic Methods (Operator Overloading)

Python魔术方法(运算符重载)

python
class Money:
    """Money class with operator overloading."""

    def __init__(self, amount: float, currency: str = "USD"):
        self.amount = amount
        self.currency = currency

    def __add__(self, other):
        """Add two money amounts."""
        if isinstance(other, Money):
            if self.currency != other.currency:
                raise ValueError("Cannot add different currencies")
            return Money(self.amount + other.amount, self.currency)
        elif isinstance(other, (int, float)):
            return Money(self.amount + other, self.currency)
        return NotImplemented

    def __sub__(self, other):
        """Subtract two money amounts."""
        if isinstance(other, Money):
            if self.currency != other.currency:
                raise ValueError("Cannot subtract different currencies")
            return Money(self.amount - other.amount, self.currency)
        elif isinstance(other, (int, float)):
            return Money(self.amount - other, self.currency)
        return NotImplemented

    def __mul__(self, other):
        """Multiply money by a number."""
        if isinstance(other, (int, float)):
            return Money(self.amount * other, self.currency)
        return NotImplemented

    def __truediv__(self, other):
        """Divide money by a number."""
        if isinstance(other, (int, float)):
            if other == 0:
                raise ValueError("Cannot divide by zero")
            return Money(self.amount / other, self.currency)
        return NotImplemented

    def __eq__(self, other):
        """Check equality."""
        if not isinstance(other, Money):
            return False
        return self.amount == other.amount and self.currency == other.currency

    def __lt__(self, other):
        """Less than comparison."""
        if not isinstance(other, Money):
            return NotImplemented
        if self.currency != other.currency:
            raise ValueError("Cannot compare different currencies")
        return self.amount < other.amount

    def __le__(self, other):
        """Less than or equal comparison."""
        return self == other or self < other

    def __gt__(self, other):
        """Greater than comparison."""
        if not isinstance(other, Money):
            return NotImplemented
        if self.currency != other.currency:
            raise ValueError("Cannot compare different currencies")
        return self.amount > other.amount

    def __ge__(self, other):
        """Greater than or equal comparison."""
        return self == other or self > other

    def __str__(self):
        """String representation."""
        return f"{self.currency} {self.amount:.2f}"

    def __repr__(self):
        """Developer representation."""
        return f"Money({self.amount}, {self.currency!r})"

    def __hash__(self):
        """Hash for using in sets/dicts."""
        return hash((self.amount, self.currency))
python
class Money:
    """Money class with operator overloading."""

    def __init__(self, amount: float, currency: str = "USD"):
        self.amount = amount
        self.currency = currency

    def __add__(self, other):
        """Add two money amounts."""
        if isinstance(other, Money):
            if self.currency != other.currency:
                raise ValueError("Cannot add different currencies")
            return Money(self.amount + other.amount, self.currency)
        elif isinstance(other, (int, float)):
            return Money(self.amount + other, self.currency)
        return NotImplemented

    def __sub__(self, other):
        """Subtract two money amounts."""
        if isinstance(other, Money):
            if self.currency != other.currency:
                raise ValueError("Cannot subtract different currencies")
            return Money(self.amount - other.amount, self.currency)
        elif isinstance(other, (int, float)):
            return Money(self.amount - other, self.currency)
        return NotImplemented

    def __mul__(self, other):
        """Multiply money by a number."""
        if isinstance(other, (int, float)):
            return Money(self.amount * other, self.currency)
        return NotImplemented

    def __truediv__(self, other):
        """Divide money by a number."""
        if isinstance(other, (int, float)):
            if other == 0:
                raise ValueError("Cannot divide by zero")
            return Money(self.amount / other, self.currency)
        return NotImplemented

    def __eq__(self, other):
        """Check equality."""
        if not isinstance(other, Money):
            return False
        return self.amount == other.amount and self.currency == other.currency

    def __lt__(self, other):
        """Less than comparison."""
        if not isinstance(other, Money):
            return NotImplemented
        if self.currency != other.currency:
            raise ValueError("Cannot compare different currencies")
        return self.amount < other.amount

    def __le__(self, other):
        """Less than or equal comparison."""
        return self == other or self < other

    def __gt__(self, other):
        """Greater than comparison."""
        if not isinstance(other, Money):
            return NotImplemented
        if self.currency != other.currency:
            raise ValueError("Cannot compare different currencies")
        return self.amount > other.amount

    def __ge__(self, other):
        """Greater than or equal comparison."""
        return self == other or self > other

    def __str__(self):
        """String representation."""
        return f"{self.currency} {self.amount:.2f}"

    def __repr__(self):
        """Developer representation."""
        return f"Money({self.amount}, {self.currency!r})"

    def __hash__(self):
        """Hash for using in sets/dicts."""
        return hash((self.amount, self.currency))

Usage

Usage

price = Money(19.99) tax = Money(2.00) total = price + tax # Money(21.99, 'USD') discounted = total * 0.9 # Money(19.791, 'USD') print(total > price) # True
undefined
price = Money(19.99) tax = Money(2.00) total = price + tax # Money(21.99, 'USD') discounted = total * 0.9 # Money(19.791, 'USD') print(total > price) # True
undefined

Duck Typing and Structural Polymorphism

鸭子类型与结构化多态

Duck Typing in Python

Python中的鸭子类型

python
undefined
python
undefined

No explicit interface - objects just need the right methods

No explicit interface - objects just need the right methods

class FileWriter: """Writes to a file."""
def __init__(self, filename: str):
    self.file = open(filename, 'w')

def write(self, data: str) -> None:
    self.file.write(data)

def close(self) -> None:
    self.file.close()
class StringWriter: """Writes to a string buffer."""
def __init__(self):
    self.buffer = []

def write(self, data: str) -> None:
    self.buffer.append(data)

def close(self) -> None:
    pass  # Nothing to close

def get_value(self) -> str:
    return ''.join(self.buffer)
class NetworkWriter: """Writes to a network socket."""
def __init__(self, host: str, port: int):
    self.host = host
    self.port = port
    self.connected = True

def write(self, data: str) -> None:
    print(f"Sending to {self.host}:{self.port}: {data}")

def close(self) -> None:
    self.connected = False
    print("Connection closed")
class FileWriter: """Writes to a file."""
def __init__(self, filename: str):
    self.file = open(filename, 'w')

def write(self, data: str) -> None:
    self.file.write(data)

def close(self) -> None:
    self.file.close()
class StringWriter: """Writes to a string buffer."""
def __init__(self):
    self.buffer = []

def write(self, data: str) -> None:
    self.buffer.append(data)

def close(self) -> None:
    pass  # Nothing to close

def get_value(self) -> str:
    return ''.join(self.buffer)
class NetworkWriter: """Writes to a network socket."""
def __init__(self, host: str, port: int):
    self.host = host
    self.port = port
    self.connected = True

def write(self, data: str) -> None:
    print(f"Sending to {self.host}:{self.port}: {data}")

def close(self) -> None:
    self.connected = False
    print("Connection closed")

Function that works with any "writer-like" object

Function that works with any "writer-like" object

def save_report(writer, title: str, data: List[str]) -> None: """Save report using any writer (duck typing).""" writer.write(f"Report: {title}\n") writer.write("=" * 50 + "\n")
for item in data:
    writer.write(f"- {item}\n")

writer.close()
def save_report(writer, title: str, data: List[str]) -> None: """Save report using any writer (duck typing).""" writer.write(f"Report: {title}\n") writer.write("=" * 50 + "\n")
for item in data:
    writer.write(f"- {item}\n")

writer.close()

All work with the same function

All work with the same function

save_report(FileWriter("report.txt"), "Sales", ["Item 1", "Item 2"]) save_report(StringWriter(), "Inventory", ["Product A", "Product B"]) save_report(NetworkWriter("server.com", 8080), "Metrics", ["CPU: 50%"])
undefined
save_report(FileWriter("report.txt"), "Sales", ["Item 1", "Item 2"]) save_report(StringWriter(), "Inventory", ["Product A", "Product B"]) save_report(NetworkWriter("server.com", 8080), "Metrics", ["CPU: 50%"])
undefined

When to Use This Skill

何时使用本技能

Apply polymorphism when:
  1. Building extensible plugin architectures
  2. Creating interchangeable implementations
  3. Writing code against interfaces/abstractions
  4. Implementing the strategy pattern
  5. Building dependency injection systems
  6. Creating framework hooks and extension points
  7. Supporting multiple data formats or protocols
  8. Implementing command patterns
  9. Building notification or messaging systems
  10. Creating abstract data access layers
  11. Supporting multiple rendering engines
  12. Implementing visitor patterns
  13. Building state machines with polymorphic states
  14. Creating factory methods that return polymorphic types
  15. Designing testable code with mock objects
在以下场景中应用多态性:
  1. 构建可扩展的插件架构
  2. 创建可互换的实现
  3. 编写基于接口/抽象的代码
  4. 实现策略模式
  5. 构建依赖注入系统
  6. 创建框架钩子和扩展点
  7. 支持多种数据格式或协议
  8. 实现命令模式
  9. 构建通知或消息系统
  10. 创建抽象数据访问层
  11. 支持多种渲染引擎
  12. 实现访问者模式
  13. 构建具备多态状态的状态机
  14. 创建返回多态类型的工厂方法
  15. 设计可测试的代码(使用模拟对象)

Best Practices

最佳实践

  1. Program to interfaces, not implementations
  2. Use abstract base classes for shared behavior
  3. Keep interfaces small and focused (ISP)
  4. Use polymorphism to eliminate switch statements
  5. Favor composition over inheritance for flexibility
  6. Make polymorphic methods virtual/abstract appropriately
  7. Use dependency injection for polymorphic dependencies
  8. Document the contract/behavior expected from implementations
  9. Provide default implementations where sensible
  10. Use generics with polymorphism for type safety
  11. Override equality methods when overriding operators
  12. Keep polymorphic hierarchies shallow
  13. Use factory patterns to create polymorphic objects
  14. Test each implementation of a polymorphic interface
  15. Consider using protocols/structural typing for flexibility
  1. 针对接口编程,而非针对实现编程
  2. 使用抽象基类实现共享行为
  3. 保持接口小巧且聚焦(接口隔离原则,ISP)
  4. 使用多态性消除switch语句
  5. 优先使用组合而非继承以提升灵活性
  6. 合理将多态方法设为虚拟/抽象
  7. 对多态依赖使用依赖注入
  8. 记录实现所需遵循的契约/行为
  9. 在合理的情况下提供默认实现
  10. 结合泛型与多态性以保证类型安全
  11. 重载运算符时同时重写相等性方法
  12. 保持多态层次结构简洁
  13. 使用工厂模式创建多态对象
  14. 测试多态接口的每个实现
  15. 考虑使用协议/结构化类型以提升灵活性

Common Pitfalls

常见陷阱

  1. Breaking Liskov Substitution Principle
  2. Creating too many small interfaces
  3. Not providing consistent behavior across implementations
  4. Overusing inheritance for polymorphism
  5. Forgetting to override Object methods (equals, hashCode)
  6. Creating leaky abstractions
  7. Mixing abstraction levels in interfaces
  8. Not handling null/None in polymorphic code
  9. Creating circular dependencies between polymorphic types
  10. Overloading methods with similar but different semantics
  11. Not considering performance of virtual method calls
  12. Using reflection instead of polymorphism
  13. Creating god interfaces with too many methods
  14. Not testing substitutability of implementations
  15. Coupling to concrete types instead of abstractions
  1. 违反里氏替换原则
  2. 创建过多小型接口
  3. 不同实现间行为不一致
  4. 过度使用继承实现多态
  5. 重写运算符时忘记重写Object方法(equals、hashCode)
  6. 创建泄露的抽象
  7. 在接口中混合不同抽象层级
  8. 未在多态代码中处理null/None
  9. 在多态类型间创建循环依赖
  10. 重载语义相似但不同的方法
  11. 未考虑虚方法调用的性能
  12. 使用反射而非多态性
  13. 创建包含过多方法的上帝接口
  14. 未测试实现的可替换性
  15. 耦合到具体类型而非抽象

Resources

参考资源