一键导入
design-patterns
GoF and enterprise design patterns for Spring Boot applications with Java examples
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
GoF and enterprise design patterns for Spring Boot applications with Java examples
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when implementing Spring Boot 3.x applications. Provides hands-on implementation patterns for web, data, security, testing, and cloud-native development.
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks "review API", "check endpoints", "REST review", or before releasing API changes.
Use when designing Spring Boot 3.x application architecture, making technology decisions, or planning project structure. Provides architectural patterns and references for project setup, JPA, security, testing, and reactive programming.
Use when designing, reviewing, or modifying REST API endpoints to enforce proper HTTP verbs, status codes, versioning, and API contract best practices.
Use when reviewing or writing code to enforce DRY, KISS, and YAGNI principles with Java-specific guidance.
Use when implementing or reviewing code that benefits from established design patterns like Builder, Factory, Strategy, Observer, Decorator, or Adapter.
| name | design-patterns |
| description | GoF and enterprise design patterns for Spring Boot applications with Java examples |
// For complex object construction
public record SearchCriteria(
String query,
List<String> categories,
BigDecimal minPrice,
BigDecimal maxPrice,
SortField sortBy,
SortDirection direction,
int page,
int size
) {
public static Builder builder() { return new Builder(); }
public static class Builder {
private String query;
private List<String> categories = List.of();
private BigDecimal minPrice;
private BigDecimal maxPrice;
private SortField sortBy = SortField.RELEVANCE;
private SortDirection direction = SortDirection.DESC;
private int page = 0;
private int size = 20;
public Builder query(String query) { this.query = query; return this; }
public Builder categories(List<String> categories) { this.categories = categories; return this; }
public Builder priceRange(BigDecimal min, BigDecimal max) {
this.minPrice = min; this.maxPrice = max; return this;
}
public Builder sortBy(SortField field, SortDirection dir) {
this.sortBy = field; this.direction = dir; return this;
}
public Builder page(int page, int size) {
this.page = page; this.size = size; return this;
}
public SearchCriteria build() {
return new SearchCriteria(query, categories, minPrice, maxPrice,
sortBy, direction, page, size);
}
}
}
// Spring-powered factory using dependency injection
public interface NotificationSender {
void send(Notification notification);
NotificationType supportedType();
}
@Component
public class EmailNotificationSender implements NotificationSender {
public void send(Notification notification) { /* send email */ }
public NotificationType supportedType() { return NotificationType.EMAIL; }
}
@Component
public class SmsNotificationSender implements NotificationSender {
public void send(Notification notification) { /* send SMS */ }
public NotificationType supportedType() { return NotificationType.SMS; }
}
@Component
public class NotificationSenderFactory {
private final Map<NotificationType, NotificationSender> senders;
public NotificationSenderFactory(List<NotificationSender> senderList) {
this.senders = senderList.stream()
.collect(Collectors.toMap(NotificationSender::supportedType, Function.identity()));
}
public NotificationSender getSender(NotificationType type) {
return Optional.ofNullable(senders.get(type))
.orElseThrow(() -> new UnsupportedOperationException(
"No sender for type: " + type));
}
}
// Layered service decoration for cross-cutting concerns
public interface OrderService {
OrderDto createOrder(CreateOrderRequest request);
}
@Service
@Primary
@RequiredArgsConstructor
public class LoggingOrderService implements OrderService {
private final OrderService delegate;
@Override
public OrderDto createOrder(CreateOrderRequest request) {
log.info("Creating order for customer={}", request.customerId());
var result = delegate.createOrder(request);
log.info("Order created with id={}", result.id());
return result;
}
}
@Service
@RequiredArgsConstructor
public class DefaultOrderService implements OrderService {
@Override
public OrderDto createOrder(CreateOrderRequest request) {
// core business logic
}
}
// Adapt external API to internal interface
public interface PaymentGateway {
PaymentResult charge(PaymentRequest request);
}
@Component
@RequiredArgsConstructor
public class StripePaymentAdapter implements PaymentGateway {
private final StripeClient stripeClient;
@Override
public PaymentResult charge(PaymentRequest request) {
var stripeRequest = StripeChargeRequest.builder()
.amount(request.amount().multiply(new BigDecimal("100")).longValue())
.currency(request.currency().toLowerCase())
.source(request.paymentMethodId())
.build();
var response = stripeClient.createCharge(stripeRequest);
return new PaymentResult(
response.getId(),
mapStatus(response.getStatus()),
request.amount());
}
private PaymentStatus mapStatus(String stripeStatus) {
return switch (stripeStatus) {
case "succeeded" -> PaymentStatus.COMPLETED;
case "pending" -> PaymentStatus.PENDING;
default -> PaymentStatus.FAILED;
};
}
}
public interface PricingStrategy {
BigDecimal calculatePrice(Product product, Customer customer);
boolean appliesTo(CustomerType type);
}
@Component
public class RegularPricing implements PricingStrategy {
public BigDecimal calculatePrice(Product product, Customer customer) {
return product.getBasePrice();
}
public boolean appliesTo(CustomerType type) {
return type == CustomerType.REGULAR;
}
}
@Component
public class PremiumPricing implements PricingStrategy {
public BigDecimal calculatePrice(Product product, Customer customer) {
return product.getBasePrice().multiply(new BigDecimal("0.85"));
}
public boolean appliesTo(CustomerType type) {
return type == CustomerType.PREMIUM;
}
}
@Service
@RequiredArgsConstructor
public class PricingService {
private final List<PricingStrategy> strategies;
public BigDecimal getPrice(Product product, Customer customer) {
return strategies.stream()
.filter(s -> s.appliesTo(customer.getType()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No pricing strategy"))
.calculatePrice(product, customer);
}
}
// Domain event
public record OrderStatusChangedEvent(
String orderId,
OrderStatus previousStatus,
OrderStatus newStatus,
Instant occurredAt
) {}
// Publisher
@Service
public class OrderService {
private final ApplicationEventPublisher publisher;
@Transactional
public void updateStatus(String orderId, OrderStatus newStatus) {
var order = orderRepository.findById(orderId).orElseThrow();
var previous = order.getStatus();
order.setStatus(newStatus);
orderRepository.save(order);
publisher.publishEvent(new OrderStatusChangedEvent(
orderId, previous, newStatus, Instant.now()));
}
}
// Listeners
@Component
public class OrderStatusListeners {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@Async
public void onStatusChanged(OrderStatusChangedEvent event) {
// send notification, update analytics, etc.
}
}
public abstract class AbstractDataImporter<T> {
public final ImportResult importData(InputStream source) {
var rawRecords = parseSource(source);
var validRecords = rawRecords.stream()
.filter(this::validate)
.map(this::transform)
.toList();
return persist(validRecords);
}
protected abstract List<Map<String, String>> parseSource(InputStream source);
protected abstract boolean validate(Map<String, String> record);
protected abstract T transform(Map<String, String> record);
protected abstract ImportResult persist(List<T> records);
}
@Component
public class ProductCsvImporter extends AbstractDataImporter<Product> {
@Override
protected List<Map<String, String>> parseSource(InputStream source) { /* CSV parsing */ }
@Override
protected boolean validate(Map<String, String> record) { /* validation */ }
@Override
protected Product transform(Map<String, String> record) { /* mapping */ }
@Override
protected ImportResult persist(List<Product> records) { /* batch save */ }
}
| Problem | Pattern | Spring Integration |
|---|---|---|
| Multiple implementations | Strategy | List<Interface> injection |
| Object creation logic | Factory | @Component factory with DI |
| Cross-cutting concerns | Decorator | @Primary + delegation |
| External system integration | Adapter | @Component adapter |
| React to state changes | Observer | ApplicationEventPublisher |
| Complex object construction | Builder | Static builder() method |
| Step-based processing | Template Method | Abstract class with final template |