Community编程与开发github.com

viccom/设计模式

包含 Java 示例的常见设计模式(工厂、构建器、策略、观察者、装饰器等)。当用户要求“实现模式”、“使用工厂”、“策略模式”或设计可扩展组件时使用。

设计模式 是什么?

该技能为 Java 开发者提供了一份实用、现代的设计模式参考手册,涵盖创建型、行为型和结构型模式的成熟 Java 示例,并对比了传统实现与 Spring、Lombok、Java 8+ 函数式接口等现代框架的优先做法。它帮助 AI Agent 理解何时使用 Builder、Factory、Strategy、Observer、Decorator、Singleton、Adapter 和 Template Method 等模式。文档以表格形式快速定位问题与对应模式,并提供了可直接运行的代码片段,减少样板代码的同时避免伸缩构造函数等反模式。支持在 Claude Code、Cursor、Codex 等平台上使用,适用于实现新组件、重构僵化代码或进行代码审查等场景,帮助开发者编写更灵活、可维护的 Java 代码。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/viccom/viccom-agent-skills/tree/HEAD/skills/design-patterns

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

设计模式技能

实用的 Java 设计模式参考,附带现代示例。

使用时机

  • 用户要求实现特定模式
  • 设计可扩展/灵活的组件
  • 重构僵化的代码结构
  • 代码审查建议使用模式

快速参考:何时使用何种模式

问题模式
复杂的对象构造构建器 (Builder)
无需指定类即可创建对象工厂 (Factory)
多种算法,运行时切换策略 (Strategy)
无需修改类即可添加行为装饰器 (Decorator)
通知多个对象状态变化观察者 (Observer)
确保只有一个实例单例 (Singleton)
转换不兼容的接口适配器 (Adapter)
定义算法骨架模板方法 (Template Method)

创建型模式

构建器 (Builder)

使用时机: 对象参数过多,部分可选。

// ❌ 伸缩构造函数反模式
public class User {
    public User(String name) { }
    public User(String name, String email) { }
    public User(String name, String email, int age) { }
    public User(String name, String email, int age, String phone) { }
    // ... 构造函数爆炸
}

// ✅ 构建器模式
public class User {
    private final String name;      // 必需
    private final String email;     // 必需
    private final int age;          // 可选
    private final String phone;     // 可选
    private final String address;   // 可选

    private User(Builder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public static Builder builder(String name, String email) {
        return new Builder(name, email);
    }

    public static class Builder {
        // 必需
        private final String name;
        private final String email;
        // 可选,带默认值
        private int age = 0;
        private String phone = "";
        private String address = "";

        private Builder(String name, String email) {
            this.name = name;
            this.email = email;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}

// 使用
User user = User.builder("John", "[email protected]")
    .age(30)
    .phone("+1234567890")
    .build();

使用 Lombok:

@Builder
@Getter
public class User {
    private final String name;
    private final String email;
    @Builder.Default private int age = 0;
    private String phone;
}

工厂方法 (Factory Method)

使用时机: 需要创建对象但不指定具体类。

// ✅ 工厂方法模式
public interface Notification {
    void send(String message);
}

public class EmailNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("Email: " + message);
    }
}

public class SmsNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("SMS: " + message);
    }
}

public class PushNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("Push: " + message);
    }
}

// 工厂
public class NotificationFactory {

    public static Notification create(String type) {
        return switch (type.toUpperCase()) {
            case "EMAIL" -> new EmailNotification();
            case "SMS" -> new SmsNotification();
            case "PUSH" -> new PushNotification();
            default -> throw new IllegalArgumentException("未知类型: " + type);
        };
    }
}

// 使用
Notification notification = NotificationFactory.create("EMAIL");
notification.send("Hello!");

使用 Spring(推荐):

public interface NotificationSender {
    void send(String message);
    String getType();
}

@Component
public class EmailSender implements NotificationSender {
    @Override public void send(String message) { /* ... */ }
    @Override public String getType() { return "EMAIL"; }
}

@Component
public class SmsSender implements NotificationSender {
    @Override public void send(String message) { /* ... */ }
    @Override public String getType() { return "SMS"; }
}

@Component
public class NotificationFactory {
    private final Map<String, NotificationSender> senders;

    public NotificationFactory(List<NotificationSender> senderList) {
        this.senders = senderList.stream()
            .collect(Collectors.toMap(
                NotificationSender::getType,
                Function.identity()
            ));
    }

    public NotificationSender getSender(String type) {
        return Optional.ofNullable(senders.get(type))
            .orElseThrow(() -> new IllegalArgumentException("未知: " + type));
    }
}

单例 (Singleton)

使用时机: 恰好需要一个实例(请谨慎使用!)。

// ✅ 现代单例(基于枚举,线程安全)
public enum DatabaseConnection {
    INSTANCE;

    private Connection connection;

    DatabaseConnection() {
        // 初始化连接
    }

    public Connection getConnection() {
        return connection;
    }
}

// 使用
Connection conn = DatabaseConnection.INSTANCE.getConnection();

使用 Spring(推荐):

@Component  // 默认作用域是单例
public class DatabaseConnection {
    // Spring 管理单个实例
}

警告: 单例可能带来问题:

  • 难以测试(全局状态)
  • 隐藏依赖
  • 考虑使用依赖注入替代

行为型模式

策略 (Strategy)

使用时机: 同一操作有多种算法,需要在运行时切换。

// ✅ 策略模式
public interface PaymentStrategy {
    void pay(BigDecimal amount);
}

public class CreditCardPayment implements PaymentStrategy {
    private final String cardNumber;

    public CreditCardPayment(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(BigDecimal amount) {
        System.out.println("Paid " + amount + " with card " + cardNumber);
    }
}

public class PayPalPayment implements PaymentStrategy {
    private final String email;

    public PayPalPayment(String email) {
        this.email = email;
    }

    @Override
    public void pay(BigDecimal amount) {
        System.out.println("Paid " + amount + " via PayPal: " + email);
    }
}

public class CryptoPayment implements PaymentStrategy {
    private final String walletAddress;

    public CryptoPayment(String walletAddress) {
        this.walletAddress = walletAddress;
    }

    @Override
    public void pay(BigDecimal amount) {
        System.out.println("Paid " + amount + " to wallet: " + walletAddress);
    }
}

// 上下文
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }

    public void checkout(BigDecimal total) {
        paymentStrategy.pay(total);
    }
}

// 使用
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment("4111-1111-1111-1111"));
cart.checkout(new BigDecimal("99.99"));

// 运行时切换策略
cart.setPaymentStrategy(new PayPalPayment("[email protected]"));
cart.checkout(new BigDecimal("49.99"));

使用 Java 8+(函数式):

// 策略作为函数式接口
@FunctionalInterface
public interface PaymentStrategy {
    void pay(BigDecimal amount);
}

// 使用 Lambda
PaymentStrategy creditCard = amount ->
    System.out.println("Card payment: " + amount);

PaymentStrategy paypal = amount ->
    System.out.println("PayPal payment: " + amount);

cart.setPaymentStrategy(creditCard);

观察者 (Observer)

使用时机: 对象需要被通知另一个对象的更改。

// ✅ 观察者模式(现代 Java)
public interface OrderObserver {
    void onOrderPlaced(Order order);
}

public class OrderService {
    private final List<OrderObserver> observers = new ArrayList<>();

    public void addObserver(OrderObserver observer) {
        observers.add(observer);
    }

    public void removeObserver(OrderObserver observer) {
        observers.remove(observer);
    }

    public void placeOrder(Order order) {
        // 处理订单
        saveOrder(order);

        // 通知所有观察者
        observers.forEach(observer -> observer.onOrderPlaced(order));
    }
}

// 观察者
public class InventoryService implements OrderObserver {
    @Override
    public void onOrderPlaced(Order order) {
        // 减少库存
        order.getItems().forEach(item ->
            reduceStock(item.getProductId(), item.getQuantity())
        );
    }
}

public class EmailNotificationService implements OrderObserver {
    @Override
    public void onOrderPlaced(Order order) {
        sendConfirmationEmail(order.getCustomerEmail(), order);
    }
}

public class AnalyticsService implements OrderObserver {
    @Override
    public void onOrderPlaced(Order order) {
        trackOrderEvent(order);
    }
}

// 设置
OrderService orderService = new OrderService();
orderService.addObserver(new InventoryService());
orderService.addObserver(new EmailNotificationService());
orderService.addObserver(new AnalyticsService());

使用 Spring 事件(推荐):

// 事件
public record OrderPlacedEvent(Order order) {}

// 发布者
@Service
public class OrderService {
    private final ApplicationEventPublisher eventPublisher;

    public void placeOrder(Order order) {
        saveOrder(order);
        eventPublisher.publishEvent(new OrderPlacedEvent(order));
    }
}

// 监听器(观察者)
@Component
public class InventoryListener {
    @EventListener
    public void handleOrderPlaced(OrderPlacedEvent event) {
        // 减少库存
    }
}

@Component
public class EmailListener {
    @EventListener
    public void handleOrderPlaced(OrderPlacedEvent event) {
        // 发送邮件
    }

    @EventListener
    @Async  // 异步处理
    public void handleOrderPlacedAsync(OrderPlacedEvent event) {
        // 异步发送邮件
    }
}

模板方法 (Template Method)

使用时机: 定义算法骨架,让子类填充步骤。

// ✅ 模板方法模式
public abstract class DataProcessor {

    // 模板方法 - 定义算法
    public final void process() {
        readData();
        processData();
        writeData();
        if (shouldNotify()) {
            notifyCompletion();
        }
    }

    // 由子类实现的步骤
    protected abstract void readData();
    protected abstract void processData();
    protected abstract void writeData();

    // 钩子 - 可选的覆盖
    protected boolean shouldNotify() {
        return true;
    }

    protected void notifyCompletion() {
        System.out.println("Processing completed!");
    }
}

public class CsvDataProcessor extends DataProcessor {
    @Override
    protected void readData() {
        System.out.println("Reading CSV file...");
    }

    @Override
    protected void processData() {
        System.out.println("Processing CSV data...");
    }

    @Override
    protected void writeData() {
        System.out.println("Writing to database...");
    }
}

public class ApiDataProcessor extends DataProcessor {
    @Override
    protected void readData() {
        System.out.println("Fetching from API...");
    }

    @Override
    protected void processData() {
        System.out.println("Transforming API response...");
    }

    @Override
    protected void writeData() {
        System.out.println("Writing to cache...");
    }

    @Override
    protected boolean shouldNotify() {
        return false;  // 覆盖钩子
    }
}

// 使用
DataProcessor csvProcessor = new CsvDataProcessor();
csvProcessor.process();

DataProcessor apiProcessor = new ApiDataProcessor();
apiProcessor.process();

结构型模式

装饰器 (Decorator)

使用时机: 不修改现有类,动态添加行为。

// ✅ 装饰器模式
public interface Coffee {
    String getDescription();
    BigDecimal getCost();
}

public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Coffee";
    }

    @Override
    public BigDecimal getCost() {
        return new BigDecimal("2.00");
    }
}

// 基础装饰器
public abstract class CoffeeDecorator implements Coffee {
    protected final Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

    @Override
    public BigDecimal getCost() {
        return coffee.getCost();
    }
}

// 具体装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }

    @Override
    public BigDecimal getCost() {
        return coffee.getCost().add(new BigDecimal("0.50"));
    }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }

    @Override
    public BigDecimal getCost() {
        return coffee.getCost().add(new BigDecimal("0.20"));
    }
}

public class WhippedCreamDecorator extends CoffeeDecorator {
    public WhippedCreamDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Whipped Cream";
    }

    @Override
    public BigDecimal getCost() {
        return coffee.getCost().add(new BigDecimal("0.70"));
    }
}

// 使用
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription() + " $" + coffee.getCost());

coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
coffee = new WhippedCreamDecorator(coffee);
System.out.println(coffee.getDescription() + " $" + coffee.getCost());
// 输出:Coffee, Milk, Sugar, Whipped Cream $3.40

适配器 (Adapter)

使用时机: 让不兼容的接口协同工作。

// ✅ 适配器模式
// 现有接口
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) {
        // 内置支持播放 mp3
        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. " + audioType + " format not supported");
        }
    }
}

// 使用
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond_the_horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far_far_away.vlc");
audioPlayer.play("avi", "mind_me.avi");

反模式与陷阱

何时应该避免使用模式

陷阱修复
过度设计编码前先简单测试
模式崇拜解决问题,不要强套模式
过早抽象重复三次后再考虑抽象
接口臃肿接口要保持专注(接口隔离原则,ISP)

选择模式的检查清单

  1. 这是什么类型的问题?(创建型、结构型、行为型)
  2. 变化在哪里?(封装变化点)
  3. 复杂度是否值得?(能否用更简单的方案解决?)
  4. 模式会提高还是降低可读性?(团队是否熟悉该模式?)
  5. 能否利用框架已有的支持?(Spring、Java 8+ 特性)

最佳实践

现代 Java 与框架

  1. 优先使用库函数: 在自定义实现之前,先考虑 Stream API、Optional、java.util.function 包。
  2. 利用框架: Spring 的 IoC 容器已经实现了工厂、单例和观察者模式。
  3. 注解胜过继承: 尽可能使用 Lombok 的 @Builder 和 Spring 的 @EventListener。
  4. 考虑函数式等价方案: Lambda 和方法引用通常可以替代策略和命令模式。
  5. 模式组合: 模式可以组合使用(例如,工厂与策略、构建器与装饰器)。

测试考虑

  • 策略: 每个策略应该可以独立测试。
  • 观察者: 测试事件发布,而非监听器实现。
  • 构建器: 测试部分对象创建(可选参数留空)。
  • 工厂: 工厂的测试应只返回模拟对象(Mock)。
  • 单例: 在测试中使用依赖注入覆盖单例实例。

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

相关技能