常用Java设计模式及实践应用


设计模式是经过验证的、可重用的解决方案,能够帮助我们构建灵活、可维护的软件系统。作为Java开发者,理解并正确应用设计模式是提升代码质量的重要途径。本文将介绍几种常用的设计模式及其在实际Java项目中的应用。

创建型模式

创建型模式关注对象的创建过程,帮助我们以适当的方式创建对象。

单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供全局访问点。

// 懒汉式单例(线程安全,双重检查锁定)
public class DatabaseConnection {
    private static volatile DatabaseConnection instance;
    
    private String connectionString;
    
    private DatabaseConnection() {
        // 私有构造函数,防止外部实例化
        connectionString = "jdbc:mysql://localhost:3306/mydb";
    }
    
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnection.class) {
                if (instance == null) {
                    instance = new DatabaseConnection();
                }
            }
        }
        return instance;
    }
    
    public void connect() {
        System.out.println("连接到数据库: " + connectionString);
    }
}

// 使用
DatabaseConnection.getInstance().connect();

枚举实现单例,更简洁且线程安全:

public enum ConfigManager {
    INSTANCE;
    
    private Properties properties;
    
    ConfigManager() {
        properties = new Properties();
        try {
            properties.load(new FileInputStream("config.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public String getProperty(String key) {
        return properties.getProperty(key);
    }
}

// 使用
String serverUrl = ConfigManager.INSTANCE.getProperty("server.url");

工厂方法模式(Factory Method Pattern)

工厂方法模式定义一个创建对象的接口,但让子类决定实例化哪个类。

// 产品接口
public interface Payment {
    void processPayment(double amount);
}

// 具体产品
public class CreditCardPayment implements Payment {
    @Override
    public void processPayment(double amount) {
        System.out.println("使用信用卡支付: " + amount);
    }
}

public class PayPalPayment implements Payment {
    @Override
    public void processPayment(double amount) {
        System.out.println("使用PayPal支付: " + amount);
    }
}

// 工厂接口
public interface PaymentFactory {
    Payment createPayment();
}

// 具体工厂
public class CreditCardPaymentFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        return new CreditCardPayment();
    }
}

public class PayPalPaymentFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        return new PayPalPayment();
    }
}

// 客户端代码
public class PaymentProcessor {
    private PaymentFactory factory;
    
    public PaymentProcessor(PaymentFactory factory) {
        this.factory = factory;
    }
    
    public void processPayment(double amount) {
        Payment payment = factory.createPayment();
        payment.processPayment(amount);
    }
}

// 使用
PaymentProcessor processor = new PaymentProcessor(new CreditCardPaymentFactory());
processor.processPayment(100.50);

建造者模式(Builder Pattern)

建造者模式用于创建复杂对象,将构造过程与表示分离,同一构造过程可创建不同表示。

public class User {
    // 必要参数
    private final String firstName;
    private final String lastName;
    
    // 可选参数
    private final int age;
    private final String phone;
    private final String address;
    private final String email;
    
    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
        this.email = builder.email;
    }
    
    // Getter方法
    
    // 静态内部Builder类
    public static class UserBuilder {
        // 必要参数
        private final String firstName;
        private final String lastName;
        
        // 可选参数 - 使用默认值初始化
        private int age = 0;
        private String phone = "";
        private String address = "";
        private String email = "";
        
        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }
        
        public UserBuilder email(String email) {
            this.email = email;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

// 使用
User user = new User.UserBuilder("John", "Doe")
    .age(30)
    .phone("1234567890")
    .address("123 Street, City")
    .email("john.doe@example.com")
    .build();

结构型模式

结构型模式关注类和对象的组合,形成更大的结构,增强代码的灵活性。

适配器模式(Adapter Pattern)

适配器模式允许接口不兼容的类一起工作,将一个类的接口转换为客户端期望的另一个接口。

// 目标接口
public interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 需要适配的接口
public interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// 适配者类
public class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // 什么也不做
    }
}

public class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // 什么也不做
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file: " + fileName);
    }
}

// 适配器类
public class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

// 使用
public class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;

    @Override
    public void play(String audioType, String fileName) {
        // 内置支持
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file: " + fileName);
        }
        // 通过适配器支持其他格式
        else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media type: " + audioType);
        }
    }
}

装饰器模式(Decorator Pattern)

装饰器模式允许向现有对象添加新功能,同时不改变其结构。

// 组件接口
public interface Beverage {
    String getDescription();
    double cost();
}

// 具体组件
public class Espresso implements Beverage {
    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}

// 装饰器基类
public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
    
    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }
    
    public abstract String getDescription();
}

// 具体装饰器
public class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 牛奶";
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.30;
    }
}

public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 摩卡";
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.20;
    }
}

// 使用
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());

beverage = new Milk(beverage);
beverage = new Mocha(beverage);
System.out.println(beverage.getDescription() + " $" + beverage.cost());

行为型模式

行为型模式关注对象之间的通信方式,增强代码的可扩展性和灵活性。

策略模式(Strategy Pattern)

策略模式定义了一系列算法,并使这些算法可以互相替换。

// 策略接口
public interface SortStrategy {
    <T extends Comparable<T>> void sort(List<T> items);
}

// 具体策略
public class QuickSort implements SortStrategy {
    @Override
    public <T extends Comparable<T>> void sort(List<T> items) {
        System.out.println("使用快速排序");
        // 快速排序实现
    }
}

public class MergeSort implements SortStrategy {
    @Override
    public <T extends Comparable<T>> void sort(List<T> items) {
        System.out.println("使用归并排序");
        // 归并排序实现
    }
}

// 上下文
public class SortedList<T extends Comparable<T>> {
    private List<T> items = new ArrayList<>();
    private SortStrategy strategy;
    
    public void setSortStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void add(T item) {
        items.add(item);
    }
    
    public void sort() {
        if (strategy == null) {
            throw new IllegalStateException("Sort strategy not set");
        }
        strategy.sort(items);
    }
}

// 使用
SortedList<Integer> list = new SortedList<>();
list.add(1);
list.add(3);
list.add(2);

// 根据数据规模选择不同的排序策略
if (list.size() > 10000) {
    list.setSortStrategy(new MergeSort());
} else {
    list.setSortStrategy(new QuickSort());
}

list.sort();

观察者模式(Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,当一个对象状态改变时,其所有依赖者都会收到通知。

// 主题接口
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

// 观察者接口
public interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// 具体主题
public class WeatherData implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
    private float humidity;
    private float pressure;
    
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    
    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }
    
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
    
    private void measurementsChanged() {
        notifyObservers();
    }
}

// 具体观察者
public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
    
    public void display() {
        System.out.println("当前条件: " + temperature + "°C 和 " + humidity + "% 湿度");
    }
}

// 使用
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);

weatherData.setMeasurements(29.2f, 65.0f, 1013.1f);

Java也提供了内置的观察者模式支持:

import java.util.Observable;
import java.util.Observer;

// 主题
public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;
    
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        setChanged();  // 标记已更改
        notifyObservers();  // 通知观察者
    }
    
    public float getTemperature() {
        return temperature;
    }
    
    public float getHumidity() {
        return humidity;
    }
    
    public float getPressure() {
        return pressure;
    }
}

// 观察者
public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Observable observable;
    
    public CurrentConditionsDisplay(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }
    
    @Override
    public void update(Observable obs, Object arg) {
        if (obs instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) obs;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }
    
    public void display() {
        System.out.println("当前条件: " + temperature + "°C 和 " + humidity + "% 湿度");
    }
}

命令模式(Command Pattern)

命令模式将请求封装为对象,允许参数化客户端请求,队列或记录请求,且支持可撤销操作。

// 命令接口
public interface Command {
    void execute();
    void undo();
}

// 接收者
public class Light {
    private String location;
    
    public Light(String location) {
        this.location = location;
    }
    
    public void on() {
        System.out.println(location + " 灯打开");
    }
    
    public void off() {
        System.out.println(location + " 灯关闭");
    }
}

// 具体命令
public class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.on();
    }
    
    @Override
    public void undo() {
        light.off();
    }
}

public class LightOffCommand implements Command {
    private Light light;
    
    public LightOffCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.off();
    }
    
    @Override
    public void undo() {
        light.on();
    }
}

// 调用者
public class RemoteControl {
    private Command[] onCommands;
    private Command[] offCommands;
    private Command undoCommand;
    
    public RemoteControl() {
        onCommands = new Command[7];
        offCommands = new Command[7];
        
        Command noCommand = new NoCommand();
        for (int i = 0; i < 7; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }
    
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    
    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
        undoCommand = onCommands[slot];
    }
    
    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
        undoCommand = offCommands[slot];
    }
    
    public void undoButtonWasPushed() {
        undoCommand.undo();
    }
}

// 使用
Light livingRoomLight = new Light("客厅");
LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);

RemoteControl remote = new RemoteControl();
remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);

System.out.println("--- 按下开灯按钮 ---");
remote.onButtonWasPushed(0);
System.out.println("--- 按下关灯按钮 ---");
remote.offButtonWasPushed(0);
System.out.println("--- 按下撤销按钮 ---");
remote.undoButtonWasPushed();

设计模式在框架中的应用

流行的Java框架大量应用了设计模式:

  1. Spring Framework

    • 依赖注入(DI)是控制反转(IoC)原则的一种实现
    • AOP(面向切面编程)使用代理模式
    • Spring MVC中的DispatcherServlet使用前端控制器模式
    • 单例模式用于创建bean
  2. Hibernate

    • 数据访问对象(DAO)模式
    • 延迟加载使用代理模式
    • SessionFactory使用工厂模式
  3. Java EE

    • MVC架构模式
    • 过滤器使用拦截过滤器模式
    • 会话Bean使用单例/多例模式

设计模式的选择原则

选择设计模式时,应该遵循以下原则:

  1. 最小惊奇原则:选择最自然、最容易理解的解决方案
  2. KISS原则(保持简单直接):除非有明确需求,否则不要引入不必要的复杂性
  3. YAGNI原则(你不会需要它):只实现当前需要的功能,避免过度设计
  4. DRY原则(不要重复自己):避免代码重复

总结

设计模式是解决软件设计中常见问题的可重用方案。正确理解和应用设计模式可以提高代码质量,增强系统的可维护性和可扩展性。然而,设计模式不是万能的,应该根据具体问题和场景选择合适的模式,避免过度设计和不必要的复杂性。

作为Java开发者,我们应该将设计模式视为工具箱中的工具,在合适的场景选择合适的工具,而不是强行套用。通过持续学习和实践,我们可以更加熟练地运用设计模式,编写出更加优雅、高效的代码。