К основному содержанию
скилл CX Codex

design-patterns · decebals — скилл для Claude Code: что делает и как установить

Справочник паттернов проектирования на Java с готовыми шаблонами кода. Помогает агенту внедрять Builder, Factory или Strategy при рефакторинге и проектировании архитектуры.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add decebals/claude-code-java --skill design-patterns -a claude-code
Открыть на GitHub

Что делает design-patterns

Скилл добавляет в контекст модели шпаргалку по паттернам проектирования в Java. Внутри собраны готовые фрагменты кода для восьми типовых шаблонов: Builder, Factory, Strategy, Decorator, Observer, Singleton, Adapter и Template Method. Когда вы просите агента структурировать класс, он опирается на проверенные реализации.

Материал учитывает современную экосистему Java. Для Builder приводятся примеры с аннотацией @Builder из библиотеки Lombok, а для фабрик и синглтонов показана замена на бины Spring Framework. При этом классический Singleton прямо отмечен как проблемный из-за трудностей с тестированием глобального состояния.

Инструкции рассчитаны именно на Java и экосистему Spring. Переносить эти рецепты на другие языки без адаптации бессмысленно, потому что подходы завязаны на возможности JVM.

Какие задачи решает

  • заменить разрастающиеся конструкторы на паттерн Builder
  • развязать создание объектов через фабричный метод
  • переключать алгоритмы на лету через паттерн Strategy
  • избежать глобального состояния при использовании Singleton

Примеры запросов агенту

  • Перепиши создание объекта User через паттерн Builder с валидацией обязательных полей.
  • Вынеси логику расчёта платежей в паттерн Strategy, чтобы менять алгоритм во время работы.
  • Сделай фабрику NotificationFactory для отправки SMS и писем через интерфейс Notification.

Как установить design-patterns

1Через Skills CLI (Vercel)

npx skills add decebals/claude-code-java --skill design-patterns -a claude-code

2Вручную: положить файлы

~/.claude/skills/design-patterns/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/design-patterns/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора10

clean-code Скилл учит агента принципам DRY, KISS и YAGNI, правилам именования и структурированию функций. Помогает при рефакторинге запутанного кода с длинными методами. CX Codex +1 379установок concurrency-review Находит гонки данных, блокировки и скрытые дефекты многопоточности в коде на Java. Проверяет как классические примитивы синхронизации, так и Virtual Threads. CX Codex +1 345установок solid-principles Скилл проверяет Java-код на соответствие принципам SOLID и помогает разгрузить разросшиеся классы. Пригодится при проектировании архитектуры и ревью дизайна. CX Codex +1 345установок architecture-review Скилл для макроразбора Java-проекта: структура пакетов, границы модулей, направление зависимостей и слои. Пригодится, когда кодовая база разрослась и непонятно, где что лежит. CX Codex +1 338установок spring-boot-patterns Скилл задаёт структуру Spring Boot-проекта и шаблоны для контроллеров, сервисов и репозиториев. Пригодится, когда агент пишет новый код или разбирает чужой. CX Codex +1 322установок java-migration Ведёт проект по цепочке LTS-версий Java: от оценки текущего состояния до правки сборки и тестов. Пригодится, когда надо перевести легаси на Java 21 или 25. CX Codex +1 321установок performance-smell-detection Находит узкие места в Java-коде: создание лишних объектов и компиляцию regex в циклах. Помогает при ревью критичных к нагрузке участков. CX Codex +1 310установок security-audit Чек-лист по OWASP Top 10 для Java-кода: проверяет валидацию ввода, SQL-инъекции, XSS и настройки безопасности. Пригодится перед релизом и при ревью авторизации. CX Codex +1 309установок

Другие версии design-patterns

Похожие

python-design-patterns Seth Hobson Помогает выбирать структуру Python-кода, разделять обязанности и решать, когда выносить повторяющуюся логику в абстракцию. Пригодится при проектировании и рефакторинге. CX Codex 22 842установок design-patterns-implementation aj-geddes Помогает агенту подобрать паттерн под архитектурную задачу: Singleton, Factory, Observer, Strategy и другие. Пригодится при рефакторинге и разборе ревью. CX Codex +1 595установок oop-design-patterns официальный github Правило для GitHub Copilot, которое подталкивает его к паттернам GoF и принципам SOLID при генерации и рефакторинге ООП-кода. ★ 40 418звёзд репо golang-design-patterns samber Скилл подсказывает идиоматичные Go-паттерны для API, жизненного цикла ресурсов, graceful shutdown и архитектуры. Пригодится при проектировании и ревью кода. CX Codex +1 42 100установок refactoring-patterns wondelai Скилл помогает улучшать структуру кода без изменения поведения, применяя названные трансформации. Пригодится, когда нужно избавиться от дублирования, распутать длинные методы или переместить ответственность между классами. CX Codex +1 6 300установок cloud-design-patterns официальный github Скилл для GitHub Copilot с 42 паттернами проектирования распределённых систем. Пригодится, когда проектируешь или разбираешь архитектуру облачной нагрузки. 2 200установок

Рядом в теме «Бэкенд и API»

Всё по теме «Бэкенд и API» →

Вопросы о design-patterns

Как установить design-patterns в Claude Code?

Выполните команду npx skills add decebals/claude-code-java --skill design-patterns -a claude-code в терминале проекта.

Что делает скилл design-patterns?

Он предоставляет агенту готовые Java-шаблоны и правила выбора между порождающими, структурными и поведенческими паттернами.

Поддерживает ли скилл фреймворки Spring и Lombok?

Да, примеры включают генерацию билдеров через аннотацию @Builder из Lombok и регистрацию фабрик через @Component в Spring.

Исходный текст

SKILL.md · MIT
---
name: design-patterns
description: Common design patterns with Java examples (Factory, Builder, Strategy, Observer, Decorator, etc.). Use when user asks "implement pattern", "use factory", "strategy pattern", or when designing extensible components.
license: MIT
---

# Design Patterns Skill

Practical design patterns reference for Java with modern examples.

## When to Use
- User asks to implement a specific pattern
- Designing extensible/flexible components
- Refactoring rigid code structures
- Code review suggests pattern usage

---

## Quick Reference: When to Use What

| Problem | Pattern |
|---------|---------|
| Complex object construction | **Builder** |
| Create objects without specifying class | **Factory** |
| Multiple algorithms, swap at runtime | **Strategy** |
| Add behavior without changing class | **Decorator** |
| Notify multiple objects of changes | **Observer** |
| Ensure single instance | **Singleton** |
| Convert incompatible interfaces | **Adapter** |
| Define algorithm skeleton | **Template Method** |

---

## Creational Patterns

### Builder

**Use when:** Object has many parameters, some optional.

```java
// ❌ Telescoping constructor antipattern
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) { }
    // ... explosion of constructors
}

// ✅ Builder pattern
public class User {
    private final String name;      // required
    private final String email;     // required
    private final int age;          // optional
    private final String phone;     // optional
    private final String address;   // optional

    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 {
        // Required
        private final String name;
        private final String email;
        // Optional with defaults
        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);
        }
    }
}

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

**With Lombok:**
```java
@Builder
@Getter
public class User {
    private final String name;
    private final String email;
    @Builder.Default private int age = 0;
    private String phone;
}
```

---

### Factory Method

**Use when:** Need to create objects without specifying exact class.

```java
// ✅ Factory Method pattern
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);
    }
}

// Factory
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("Unknown type: " + type);
        };
    }
}

// Usage
Notification notification = NotificationFactory.create("EMAIL");
notification.send("Hello!");
```

**With Spring (preferred):**
```java
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("Unknown: " + type));
    }
}
```

---

### Singleton

**Use when:** Exactly one instance needed (use sparingly!).

```java
// ✅ Modern singleton (enum-based, thread-safe)
public enum DatabaseConnection {
    INSTANCE;

    private Connection connection;

    DatabaseConnection() {
        // Initialize connection
    }

    public Connection getConnection() {
        return connection;
    }
}

// Usage
Connection conn = DatabaseConnection.INSTANCE.getConnection();
```

**With Spring (preferred):**
```java
@Component  // Default scope is singleton
public class DatabaseConnection {
    // Spring manages single instance
}
```

**Warning:** Singletons can be problematic:
- Hard to test (global state)
- Hidden dependencies
- Consider dependency injection instead

---

## Behavioral Patterns

### Strategy

**Use when:** Multiple algorithms for same operation, need to swap at runtime.

```java
// ✅ Strategy pattern
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);
    }
}

// Context
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

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

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

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

// Change strategy at runtime
cart.setPaymentStrategy(new PayPalPayment("[email protected]"));
cart.checkout(new BigDecimal("49.99"));
```

**With Java 8+ (functional):**
```java
// Strategy as functional interface
@FunctionalInterface
public interface PaymentStrategy {
    void pay(BigDecimal amount);
}

// Usage with lambdas
PaymentStrategy creditCard = amount ->
    System.out.println("Card payment: " + amount);

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

cart.setPaymentStrategy(creditCard);
```

---

### Observer

**Use when:** Objects need to be notified of changes in another object.

```java
// ✅ Observer pattern (modern 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) {
        // Process order
        saveOrder(order);

        // Notify all observers
        observers.forEach(observer -> observer.onOrderPlaced(order));
    }
}

// Observers
public class InventoryService implements OrderObserver {
    @Override
    public void onOrderPlaced(Order order) {
        // Reduce inventory
        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);
    }
}

// Setup
OrderService orderService = new OrderService();
orderService.addObserver(new InventoryService());
orderService.addObserver(new EmailNotificationService());
orderService.addObserver(new AnalyticsService());
```

**With Spring Events (preferred):**
```java
// Event
public record OrderPlacedEvent(Order order) {}

// Publisher
@Service
public class OrderService {
    private final ApplicationEventPublisher eventPublisher;

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

// Listeners (observers)
@Component
public class InventoryListener {
    @EventListener
    public void handleOrderPlaced(OrderPlacedEvent event) {
        // Reduce inventory
    }
}

@Component
public class EmailListener {
    @EventListener
    public void handleOrderPlaced(OrderPlacedEvent event) {
        // Send email
    }

    @EventListener
    @Async  // Async processing
    public void handleOrderPlacedAsync(OrderPlacedEvent event) {
        // Send email asynchronously
    }
}
```

---

### Template Method

**Use when:** Define algorithm skeleton, let subclasses fill in steps.

```java
// ✅ Template Method pattern
public abstract class DataProcessor {

    // Template method - defines the algorithm
    public final void process() {
        readData();
        processData();
        writeData();
        if (shouldNotify()) {
            notifyCompletion();
        }
    }

    // Steps to be implemented by subclasses
    protected abstract void readData();
    protected abstract void processData();
    protected abstract void writeData();

    // Hook - optional override
    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;  // Override hook
    }
}

// Usage
DataProcessor csvProcessor = new CsvDataProcessor();
csvProcessor.process();

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

---

## Structural Patterns

### Decorator

**Use when:** Add behavior dynamically without modifying existing classes.

```java
// ✅ Decorator pattern
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");
    }
}

// Base decorator
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();
    }
}

// Concrete decorators
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"));
    }
}

// Usage - compose decorators
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
coffee = new WhippedCreamDecorator(coffee);

System.out.println(coffee.getDescription());  // Coffee, Milk, Sugar, Whipped Cream
System.out.println(coffee.getCost());         // 3.40
```

**Java I/O uses Decorator:**
```java
// Classic example from Java
BufferedReader reader = new BufferedReader(
    new InputStreamReader(
        new FileInputStream("file.txt")
    )
);
```

---

### Adapter

**Use when:** Make incompatible interfaces work together.

```java
// ✅ Adapter pattern

// Existing interface our code uses
public interface MediaPlayer {
    void play(String filename);
}

// Legacy/third-party interface
public class LegacyAudioPlayer {
    public void playMp3(String filename) {
        System.out.println("Playing MP3: " + filename);
    }
}

public class AdvancedVideoPlayer {
    public void playMp4(String filename) {
        System.out.println("Playing MP4: " + filename);
    }

    public void playAvi(String filename) {
        System.out.println("Playing AVI: " + filename);
    }
}

// Adapters
public class Mp3PlayerAdapter implements MediaPlayer {
    private final LegacyAudioPlayer legacyPlayer = new LegacyAudioPlayer();

    @Override
    public void play(String filename) {
        legacyPlayer.playMp3(filename);
    }
}

public class VideoPlayerAdapter implements MediaPlayer {
    private final AdvancedVideoPlayer videoPlayer = new AdvancedVideoPlayer();

    @Override
    public void play(String filename) {
        if (filename.endsWith(".mp4")) {
            videoPlayer.playMp4(filename);
        } else if (filename.endsWith(".avi")) {
            videoPlayer.playAvi(filename);
        }
    }
}

// Usage
MediaPlayer mp3Player = new Mp3PlayerAdapter();
mp3Player.play("song.mp3");

MediaPlayer videoPlayer = new VideoPlayerAdapter();
videoPlayer.play("movie.mp4");
```

---

## Pattern Selection Guide

| Situation | Consider |
|-----------|----------|
| Object creation is complex | Builder, Factory |
| Need to add features dynamically | Decorator |
| Multiple implementations of algorithm | Strategy |
| React to state changes | Observer |
| Integrate with legacy code | Adapter |
| Common algorithm, varying steps | Template Method |
| Need single instance | Singleton (use sparingly) |

---

## Anti-Patterns to Avoid

| Anti-Pattern | Problem | Better Approach |
|--------------|---------|-----------------|
| Singleton abuse | Global state, hard to test | Dependency Injection |
| Factory everywhere | Over-engineering | Simple `new` if type is known |
| Deep decorator chains | Hard to debug | Keep chains short, consider composition |
| Observer with many events | Spaghetti notifications | Event bus, clear event hierarchy |

---

## Related Skills

- `solid-principles` - Design principles that patterns help implement
- `clean-code` - Code-level best practices
- `spring-boot-patterns` - Spring-specific implementations

© decebals · MIT · decebals/claude-code-java

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой