常用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框架大量应用了设计模式:
-
Spring Framework:
- 依赖注入(DI)是控制反转(IoC)原则的一种实现
- AOP(面向切面编程)使用代理模式
- Spring MVC中的DispatcherServlet使用前端控制器模式
- 单例模式用于创建bean
-
Hibernate:
- 数据访问对象(DAO)模式
- 延迟加载使用代理模式
- SessionFactory使用工厂模式
-
Java EE:
- MVC架构模式
- 过滤器使用拦截过滤器模式
- 会话Bean使用单例/多例模式
设计模式的选择原则
选择设计模式时,应该遵循以下原则:
- 最小惊奇原则:选择最自然、最容易理解的解决方案
- KISS原则(保持简单直接):除非有明确需求,否则不要引入不必要的复杂性
- YAGNI原则(你不会需要它):只实现当前需要的功能,避免过度设计
- DRY原则(不要重复自己):避免代码重复
总结
设计模式是解决软件设计中常见问题的可重用方案。正确理解和应用设计模式可以提高代码质量,增强系统的可维护性和可扩展性。然而,设计模式不是万能的,应该根据具体问题和场景选择合适的模式,避免过度设计和不必要的复杂性。
作为Java开发者,我们应该将设计模式视为工具箱中的工具,在合适的场景选择合适的工具,而不是强行套用。通过持续学习和实践,我们可以更加熟练地运用设计模式,编写出更加优雅、高效的代码。