Skip to content

程序设计模式详解

以下是常见设计模式的详细说明,每个模式都提供了JavaScript、Java和Python三种语言的实现示例,可通过切换标签查看不同语言的代码。

1. 单例模式 (Singleton)

单例模式确保一个类只有一个实例,并提供一个全局访问点。常用于日志记录器、配置管理器等需要唯一实例的场景。

javascript
class Singleton {
    constructor() {
        if (Singleton.instance) {
            return Singleton.instance;
        }
        Singleton.instance = this;
        // 初始化代码
        this.timestamp = new Date();
    }

    static getInstance() {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }
        return Singleton.instance;
    }

    getCreationTime() {
        return this.timestamp;
    }
}

// 使用示例
const instance1 = new Singleton();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
console.log(instance1.getCreationTime());
java
public class Singleton {
    // volatile确保多线程环境下的可见性
    private static volatile Singleton instance;
    
    // 私有构造函数防止外部实例化
    private Singleton() {
        // 初始化代码
    }
    
    // 双重检查锁定实现线程安全
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    
    // 示例方法
    public void doSomething() {
        System.out.println("Singleton instance is working");
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2); // true
        instance1.doSomething();
    }
}
python
class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            # 初始化代码
            cls._instance.timestamp = datetime.datetime.now()
        return cls._instance
    
    def get_creation_time(self):
        return self.timestamp

# 使用示例
import datetime

instance1 = Singleton()
instance2 = Singleton()
print(instance1 is instance2)  # True
print(instance1.get_creation_time())

2. 工厂模式 (Factory)

工厂模式通过工厂类封装对象创建逻辑,客户端无需知道具体产品的类名,只需知道相应的参数即可创建所需对象。

javascript
// 产品类
class Car {
  drive() {
    return 'Driving a car';
  }
}

class Bike {
  ride() {
    return 'Riding a bike';
  }
}

class Truck {
  haul() {
    return 'Hauling with a truck';
  }
}

// 工厂类
class VehicleFactory {
  createVehicle(type) {
    switch(type) {
      case 'car':
        return new Car();
      case 'bike':
        return new Bike();
      case 'truck':
        return new Truck();
      default:
        throw new Error('Invalid vehicle type');
    }
  }
}

// 使用示例
const factory = new VehicleFactory();
const myCar = factory.createVehicle('car');
console.log(myCar.drive()); // Driving a car

const myBike = factory.createVehicle('bike');
console.log(myBike.ride()); // Riding a bike
java
// 产品接口
interface Vehicle {
    String operate();
}

// 具体产品
class Car implements Vehicle {
    @Override
    public String operate() {
        return "Driving a car";
    }
}

class Bike implements Vehicle {
    @Override
    public String operate() {
        return "Riding a bike";
    }
}

// 工厂类
class VehicleFactory {
    public Vehicle createVehicle(String type) {
        switch(type) {
            case "car":
                return new Car();
            case "bike":
                return new Bike();
            default:
                throw new IllegalArgumentException("Invalid vehicle type");
        }
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        VehicleFactory factory = new VehicleFactory();
        Vehicle myCar = factory.createVehicle("car");
        System.out.println(myCar.operate()); // Driving a car
        
        Vehicle myBike = factory.createVehicle("bike");
        System.out.println(myBike.operate()); // Riding a bike
    }
}
python
# 产品类
class Car:
    def operate(self):
        return "Driving a car"

class Bike:
    def operate(self):
        return "Riding a bike"

class Truck:
    def operate(self):
        return "Hauling with a truck"

# 工厂类
class VehicleFactory:
    def create_vehicle(self, vehicle_type):
        if vehicle_type == "car":
            return Car()
        elif vehicle_type == "bike":
            return Bike()
        elif vehicle_type == "truck":
            return Truck()
        else:
            raise ValueError(f"Invalid vehicle type: {vehicle_type}")

# 使用示例
factory = VehicleFactory()
my_car = factory.create_vehicle("car")
print(my_car.operate())  # Driving a car

my_bike = factory.create_vehicle("bike")
print(my_bike.operate())  # Riding a bike

3. 策略模式 (Strategy)

策略模式定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。

javascript
// 策略接口
class PaymentStrategy {
  pay(amount) {
    throw new Error('子类必须实现pay方法');
  }
}

// 具体策略
class CreditCardPayment extends PaymentStrategy {
  constructor(cardNumber, name) {
    super();
    this.cardNumber = cardNumber;
    this.name = name;
  }
  
  pay(amount) {
    return `Paid ${amount} using credit card (${this.cardNumber}) by ${this.name}`;
  }
}

class PayPalPayment extends PaymentStrategy {
  constructor(email) {
    super();
    this.email = email;
  }
  
  pay(amount) {
    return `Paid ${amount} using PayPal (${this.email})`;
  }
}

// 上下文
class ShoppingCart {
  constructor(paymentStrategy) {
    this.items = [];
    this.paymentStrategy = paymentStrategy;
  }
  
  setPaymentStrategy(strategy) {
    this.paymentStrategy = strategy;
  }
  
  addItem(item) {
    this.items.push(item);
  }
  
  calculateTotal() {
    return this.items.reduce((total, item) => total + item.price, 0);
  }
  
  checkout() {
    const total = this.calculateTotal();
    return this.paymentStrategy.pay(total);
  }
}

// 使用示例
const creditCard = new CreditCardPayment('4111-1111-1111-1111', 'John Doe');
const cart = new ShoppingCart(creditCard);

cart.addItem({ name: 'Shirt', price: 29.99 });
cart.addItem({ name: 'Pants', price: 49.99 });

console.log(cart.checkout()); // Paid 79.98 using credit card...

// 切换支付策略
const paypal = new PayPalPayment('john.doe@example.com');
cart.setPaymentStrategy(paypal);
console.log(cart.checkout()); // Paid 79.98 using PayPal...
java
// 策略接口
interface PaymentStrategy {
    String pay(double amount);
}

// 具体策略
class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;
    private String name;
    
    public CreditCardPayment(String cardNumber, String name) {
        this.cardNumber = cardNumber;
        this.name = name;
    }
    
    @Override
    public String pay(double amount) {
        return String.format("Paid %.2f using credit card (%s) by %s", 
                           amount, cardNumber, name);
    }
}

class PayPalPayment implements PaymentStrategy {
    private String email;
    
    public PayPalPayment(String email) {
        this.email = email;
    }
    
    @Override
    public String pay(double amount) {
        return String.format("Paid %.2f using PayPal (%s)", amount, email);
    }
}

// 上下文
class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    private double total = 0;
    
    public ShoppingCart(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void addItem(double price) {
        total += price;
    }
    
    public String checkout() {
        return paymentStrategy.pay(total);
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        PaymentStrategy creditCard = new CreditCardPayment(
            "4111-1111-1111-1111", "John Doe");
        ShoppingCart cart = new ShoppingCart(creditCard);
        
        cart.addItem(29.99);
        cart.addItem(49.99);
        
        System.out.println(cart.checkout());
        
        // 切换支付策略
        PaymentStrategy paypal = new PayPalPayment("john.doe@example.com");
        cart.setPaymentStrategy(paypal);
        System.out.println(cart.checkout());
    }
}
python
# 策略接口
from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

# 具体策略
class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number, name):
        self.card_number = card_number
        self.name = name
        
    def pay(self, amount):
        return f"Paid {amount:.2f} using credit card ({self.card_number}) by {self.name}"

class PayPalPayment(PaymentStrategy):
    def __init__(self, email):
        self.email = email
        
    def pay(self, amount):
        return f"Paid {amount:.2f} using PayPal ({self.email})"

# 上下文
class ShoppingCart:
    def __init__(self, payment_strategy):
        self.items = []
        self.payment_strategy = payment_strategy
        
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
        
    def add_item(self, price):
        self.items.append(price)
        
    def calculate_total(self):
        return sum(self.items)
        
    def checkout(self):
        total = self.calculate_total()
        return self.payment_strategy.pay(total)

# 使用示例
credit_card = CreditCardPayment('4111-1111-1111-1111', 'John Doe')
cart = ShoppingCart(credit_card)

cart.add_item(29.99)
cart.add_item(49.99)

print(cart.checkout())  # Paid 79.98 using credit card...

# 切换支付策略
paypal = PayPalPayment('john.doe@example.com')
cart.set_payment_strategy(paypal)
print(cart.checkout())  # Paid 79.98 using PayPal...

4. 代理模式 (Proxy)

代理模式为其他对象提供一种代理以控制对这个对象的访问。常用于延迟加载、权限控制、日志记录等场景。

javascript
// 真实主题
class RealImage {
  constructor(filename) {
    this.filename = filename;
    this.loadFromDisk(); // 模拟加载 heavy 资源
  }
  
  loadFromDisk() {
    console.log(`Loading image: ${this.filename}`);
  }
  
  display() {
    console.log(`Displaying image: ${this.filename}`);
  }
}

// 代理
class ImageProxy {
  constructor(filename) {
    this.filename = filename;
    this.realImage = null; // 延迟初始化
  }
  
  display() {
    // 只有在需要时才创建真实对象
    if (!this.realImage) {
      this.realImage = new RealImage(this.filename);
    }
    this.realImage.display();
  }
}

// 使用示例
// 图片不会立即加载
const proxyImage = new ImageProxy('large_image.jpg');

// 第一次调用display()时才会加载图片
console.log("First display:");
proxyImage.display();

// 第二次调用display()时不会重新加载
console.log("Second display:");
proxyImage.display();
java
// 主题接口
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String filename;
    
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(); // 模拟加载 heavy 资源
    }
    
    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    
    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

// 代理
class ImageProxy implements Image {
    private String filename;
    private RealImage realImage; // 延迟初始化
    
    public ImageProxy(String filename) {
        this.filename = filename;
    }
    
    @Override
    public void display() {
        // 只有在需要时才创建真实对象
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        // 图片不会立即加载
        Image image = new ImageProxy("large_image.jpg");
        
        // 第一次调用display()时才会加载图片
        System.out.println("First display:");
        image.display();
        
        // 第二次调用display()时不会重新加载
        System.out.println("Second display:");
        image.display();
    }
}
python
# 主题接口
from abc import ABC, abstractmethod

class Image(ABC):
    @abstractmethod
    def display(self):
        pass

# 真实主题
class RealImage(Image):
    def __init__(self, filename):
        self.filename = filename
        self._load_from_disk()  # 模拟加载 heavy 资源
        
    def _load_from_disk(self):
        print(f"Loading image: {self.filename}")
        
    def display(self):
        print(f"Displaying image: {self.filename}")

# 代理
class ImageProxy(Image):
    def __init__(self, filename):
        self.filename = filename
        self._real_image = None  # 延迟初始化
        
    def display(self):
        # 只有在需要时才创建真实对象
        if self._real_image is None:
            self._real_image = RealImage(self.filename)
        self._real_image.display()

# 使用示例
# 图片不会立即加载
proxy_image = ImageProxy('large_image.jpg')

# 第一次调用display()时才会加载图片
print("First display:")
proxy_image.display()

# 第二次调用display()时不会重新加载
print("Second display:")
proxy_image.display()

5. 中介者模式 (Mediator)

中介者模式定义一个对象来封装一系列对象的交互方式。它使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

javascript
// 中介者
class ChatRoom {
  showMessage(user, message) {
    const time = new Date().toLocaleTimeString();
    const userName = user.getName();
    console.log(`[${time}] ${userName}: ${message}`);
  }
}

// 同事类
class User {
  constructor(name, chatRoom) {
    this.name = name;
    this.chatRoom = chatRoom;
  }
  
  getName() {
    return this.name;
  }
  
  sendMessage(message) {
    this.chatRoom.showMessage(this, message);
  }
}

// 使用示例
const chatRoom = new ChatRoom();

const user1 = new User("Alice", chatRoom);
const user2 = new User("Bob", chatRoom);
const user3 = new User("Charlie", chatRoom);

user1.sendMessage("Hi, everyone!");
user2.sendMessage("Hello, Alice!");
user3.sendMessage("What's up?");
java
// 中介者
class ChatRoom {
    public void showMessage(User user, String message) {
        String time = java.time.LocalTime.now().toString();
        String userName = user.getName();
        System.out.printf("[%s] %s: %s%n", time, userName, message);
    }
}

// 同事类
class User {
    private String name;
    private ChatRoom chatRoom;
    
    public User(String name, ChatRoom chatRoom) {
        this.name = name;
        this.chatRoom = chatRoom;
    }
    
    public String getName() {
        return name;
    }
    
    public void sendMessage(String message) {
        chatRoom.showMessage(this, message);
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        ChatRoom chatRoom = new ChatRoom();
        
        User user1 = new User("Alice", chatRoom);
        User user2 = new User("Bob", chatRoom);
        User user3 = new User("Charlie", chatRoom);
        
        user1.sendMessage("Hi, everyone!");
        user2.sendMessage("Hello, Alice!");
        user3.sendMessage("What's up?");
    }
}
python
import datetime

# 中介者
class ChatRoom:
    def show_message(self, user, message):
        time = datetime.datetime.now().strftime("%H:%M:%S")
        user_name = user.get_name()
        print(f"[{time}] {user_name}: {message}")

# 同事类
class User:
    def __init__(self, name, chat_room):
        self.name = name
        self.chat_room = chat_room
        
    def get_name(self):
        return self.name
        
    def send_message(self, message):
        self.chat_room.show_message(self, message)

# 使用示例
chat_room = ChatRoom()

user1 = User("Alice", chat_room)
user2 = User("Bob", chat_room)
user3 = User("Charlie", chat_room)

user1.send_message("Hi, everyone!")
user2.send_message("Hello, Alice!")
user3.send_message("What's up?")

6. 装饰者模式 (Decorator)

装饰者模式动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式比生成子类更为灵活。

javascript
// 组件接口
class Beverage {
  getDescription() {
    return 'Unknown Beverage';
  }
  
  cost() {
    return 0;
  }
}

// 具体组件
class Espresso extends Beverage {
  getDescription() {
    return 'Espresso';
  }
  
  cost() {
    return 1.99;
  }
}

class HouseBlend extends Beverage {
  getDescription() {
    return 'House Blend Coffee';
  }
  
  cost() {
    return 0.89;
  }
}

// 装饰者
class Decorator extends Beverage {
  constructor(beverage) {
    super();
    this.beverage = beverage;
  }
  
  getDescription() {
    return this.beverage.getDescription();
  }
  
  cost() {
    return this.beverage.cost();
  }
}

// 具体装饰者
class Milk extends Decorator {
  constructor(beverage) {
    super(beverage);
  }
  
  getDescription() {
    return super.getDescription() + ', Milk';
  }
  
  cost() {
    return super.cost() + 0.10;
  }
}

class Mocha extends Decorator {
  constructor(beverage) {
    super(beverage);
  }
  
  getDescription() {
    return super.getDescription() + ', Mocha';
  }
  
  cost() {
    return super.cost() + 0.20;
  }
}

// 使用示例
let beverage = new Espresso();
console.log(`${beverage.getDescription()} $${beverage.cost().toFixed(2)}`);

// 装饰Espresso
beverage = new Mocha(new Milk(new Espresso()));
console.log(`${beverage.getDescription()} $${beverage.cost().toFixed(2)}`);

// 装饰HouseBlend
beverage = new Mocha(new Mocha(new Milk(new HouseBlend())));
console.log(`${beverage.getDescription()} $${beverage.cost().toFixed(2)}`);
java
// 组件接口
abstract class Beverage {
    String description = "Unknown Beverage";
    
    public String getDescription() {
        return description;
    }
    
    public abstract double cost();
}

// 具体组件
class Espresso extends Beverage {
    public Espresso() {
        description = "Espresso";
    }
    
    @Override
    public double cost() {
        return 1.99;
    }
}

class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "House Blend Coffee";
    }
    
    @Override
    public double cost() {
        return 0.89;
    }
}

// 装饰者
abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

// 具体装饰者
class Milk extends CondimentDecorator {
    Beverage beverage;
    
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.10;
    }
}

class Mocha extends CondimentDecorator {
    Beverage beverage;
    
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.20;
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        Beverage beverage = new Espresso();
        System.out.printf("%s $%.2f%n", beverage.getDescription(), beverage.cost());
        
        // 装饰Espresso
        Beverage beverage2 = new Mocha(new Milk(new Espresso()));
        System.out.printf("%s $%.2f%n", beverage2.getDescription(), beverage2.cost());
        
        // 装饰HouseBlend
        Beverage beverage3 = new Mocha(new Mocha(new Milk(new HouseBlend())));
        System.out.printf("%s $%.2f%n", beverage3.getDescription(), beverage3.cost());
    }
}
python
# 组件接口
from abc import ABC, abstractmethod

class Beverage(ABC):
    description = "Unknown Beverage"
    
    def get_description(self):
        return self.description
    
    @abstractmethod
    def cost(self):
        pass

# 具体组件
class Espresso(Beverage):
    def __init__(self):
        self.description = "Espresso"
        
    def cost(self):
        return 1.99

class HouseBlend(Beverage):
    def __init__(self):
        self.description = "House Blend Coffee"
        
    def cost(self):
        return 0.89

# 装饰者
class CondimentDecorator(Beverage):
    @abstractmethod
    def get_description(self):
        pass

# 具体装饰者
class Milk(CondimentDecorator):
    def __init__(self, beverage):
        self.beverage = beverage
        
    def get_description(self):
        return f"{self.beverage.get_description()}, Milk"
        
    def cost(self):
        return self.beverage.cost() + 0.10

class Mocha(CondimentDecorator):
    def __init__(self, beverage):
        self.beverage = beverage
        
    def get_description(self):
        return f"{self.beverage.get_description()}, Mocha"
        
    def cost(self):
        return self.beverage.cost() + 0.20

# 使用示例
beverage = Espresso()
print(f"{beverage.get_description()} ${beverage.cost():.2f}")

# 装饰Espresso
beverage2 = Mocha(Milk(Espresso()))
print(f"{beverage2.get_description()} ${beverage2.cost():.2f}")

# 装饰HouseBlend
beverage3 = Mocha(Mocha(Milk(HouseBlend())))
print(f"{beverage3.get_description()} ${beverage3.cost():.2f}")

总结

设计模式是解决特定问题的成熟方案,掌握它们可以帮助我们:

  1. 编写更具可读性和可维护性的代码
  2. 提高代码的复用性和灵活性
  3. 便于团队成员之间的沟通(使用共同的设计语言)
  4. 更好地应对需求变化

选择合适的设计模式需要根据具体问题场景,过度使用设计模式也可能导致代码复杂化。最好的做法是理解每种模式的适用场景,在实际开发中灵活运用。

尘埃虽微,积之成集;问题虽小,记之为鉴。 雾中低语,心之所向;思绪飘渺,皆可成章。