news 2026/5/20 1:11:07

模板方法模式实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
模板方法模式实战

模板方法模式实战

引言

模板方法模式是行为型设计模式的一种,它定义了一个算法的骨架,将某些步骤延迟到子类中实现。Spring的JdbcTemplate、RestTemplate等都是模板方法模式的经典应用。本文将详细介绍模板方法模式的实现方式以及在Java/Spring中的应用场景。

一、模式结构

1.1 基本结构

public abstract class DataProcessor { // 模板方法 public final void process() { connect(); validate(); processData(); save(); disconnect(); } protected void connect() { System.out.println("Connecting to data source..."); } protected abstract void validate(); protected abstract void processData(); protected abstract void save(); protected void disconnect() { System.out.println("Disconnecting..."); } } public class FileProcessor extends DataProcessor { @Override protected void validate() { System.out.println("Validating file format..."); } @Override protected void processData() { System.out.println("Processing file data..."); } @Override protected void save() { System.out.println("Saving to database..."); } }

二、JdbcTemplate模板方法

2.1 核心结构

public abstract class JdbcAccessor { protected DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } } public class JdbcTemplate extends JdbcAccessor { public <T> T execute(ConnectionCallback<T> action) { Connection conn = null; try { conn = DataSourceUtils.getConnection(dataSource); return action.doInConnection(conn); } finally { DataSourceUtils.releaseConnection(conn, dataSource); } } public <T> T query(String sql, RowMapper<T> rowMapper) { return execute(conn -> { Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(sql); List<T> results = new ArrayList<>(); while (rs.next()) { results.add(rowMapper.mapRow(rs, rs.getRow())); } return results.isEmpty() ? null : results.get(0); } finally { closeResultSet(rs); closeStatement(stmt); } }); } private void closeResultSet(ResultSet rs) { // 关闭资源 } private void closeStatement(Statement stmt) { // 关闭语句 } }

2.2 自定义JdbcTemplate

public class EnhancedJdbcTemplate extends JdbcTemplate { public <T> T executeWithRetry(String sql, RowMapper<T> rowMapper, int maxRetries) { int attempts = 0; while (attempts < maxRetries) { try { return query(sql, rowMapper); } catch (DataAccessException e) { attempts++; if (attempts >= maxRetries) { throw e; } try { Thread.sleep(1000 * attempts); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new DataAccessException("Retry interrupted") {}; } } } return null; } }

三、RestTemplate模板

3.1 请求执行器

public class RestTemplate { private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); private final ClientHttpRequestFactory requestFactory; public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) { // 1. 创建请求 ClientHttpRequest request = createRequest( url, method, uriVariables); // 2. 填充headers和body if (requestEntity != null) { writeHeaders(request, requestEntity.getHeaders()); writeBody(request, requestEntity.getBody()); } // 3. 执行请求 ClientHttpResponse response = executeRequest(request); // 4. 处理响应 return handleResponse(response, responseType); } protected ClientHttpRequest createRequest(String url, HttpMethod method, Object... uriVariables) { URI uri = UriComponentsBuilder .fromUriString(url) .buildAndExpand(uriVariables) .toUri(); return requestFactory.createRequest(uri, method); } protected ClientHttpResponse executeRequest( ClientHttpRequest request) { try { return request.execute(); } catch (IOException e) { throw new ResourceAccessException( "I/O error on " + request.getMethod() + " request", e); } } protected <T> ResponseEntity<T> handleResponse( ClientHttpResponse response, Class<T> responseType) { // 处理响应 return null; } }

四、流程处理模板

4.1 业务流程模板

public abstract class OrderProcessTemplate { public final Order process(Order order) { validate(order); reserveStock(order); calculateAmount(order); processPayment(order); confirmOrder(order); sendNotification(order); return order; } protected void validate(Order order) { if (order.getItems().isEmpty()) { throw new IllegalArgumentException("Order is empty"); } } protected abstract void reserveStock(Order order); protected abstract void calculateAmount(Order order); protected abstract void processPayment(Order order); protected void confirmOrder(Order order) { order.setStatus(OrderStatus.CONFIRMED); order.setConfirmTime(LocalDateTime.now()); } protected void sendNotification(Order order) { System.out.println("Sending notification for order: " + order.getId()); } } @Service public class OnlineOrderProcessor extends OrderProcessTemplate { @Override protected void reserveStock(Order order) { System.out.println("Reserving stock online..."); } @Override protected void calculateAmount(Order order) { BigDecimal total = order.getItems().stream() .map(OrderItem::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); order.setTotalAmount(total); } @Override protected void processPayment(Order order) { System.out.println("Processing online payment..."); } }

4.2 数据导入模板

public abstract class DataImportTemplate { public final ImportResult importData(String filePath) { InputStream inputStream = null; try { inputStream = openFile(filePath); List<Record> records = readRecords(inputStream); validateRecords(records); List<Record> validRecords = filterValidRecords(records); return saveRecords(validRecords); } catch (Exception e) { return ImportResult.failure(e.getMessage()); } finally { closeFile(inputStream); } } protected InputStream openFile(String filePath) { try { return new FileInputStream(filePath); } catch (FileNotFoundException e) { throw new ImportException("File not found: " + filePath); } } protected abstract List<Record> readRecords(InputStream input); protected void validateRecords(List<Record> records) { for (Record record : records) { if (!isValid(record)) { throw new ValidationException( "Invalid record: " + record); } } } protected abstract boolean isValid(Record record); protected List<Record> filterValidRecords(List<Record> records) { return records.stream() .filter(this::isValid) .collect(Collectors.toList()); } protected abstract ImportResult saveRecords(List<Record> records); protected void closeFile(InputStream inputStream) { if (inputStream != null) { try { inputStream.close(); } catch (IOException ignored) {} } } }

五、Callback回调

5.1 Spring的Callback接口

@FunctionalInterface public interface JdbcCallback<T> { T doInJdbc(Connection connection) throws SQLException; } public <T> T execute(JdbcCallback<T> callback) { Connection conn = getConnection(); try { return callback.doInJdbc(conn); } finally { releaseConnection(conn); } } // 使用 jdbcTemplate.execute(conn -> { try (PreparedStatement ps = conn.prepareStatement( "SELECT * FROM users WHERE id = ?")) { ps.setLong(1, userId); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return mapToUser(rs); } } } return null; });

5.2 自定义Callback

@FunctionalInterface public interface DataProcessCallback<T, R> { R process(T data) throws Exception; } public class DataProcessTemplate { public <T, R> R execute(T input, DataProcessCallback<T, R> callback) { try { return callback.process(input); } catch (Exception e) { throw new ProcessException("Processing failed", e); } } } @Service public class OrderService { private final DataProcessTemplate template; public Order confirmOrder(Order order) { return template.execute(order, o -> { validateOrder(o); calculateTotal(o); return saveOrder(o); }); } }

六、策略与模板方法结合

6.1 策略作为模板参数

public abstract class DataExportTemplate { public final void export(List<?> data, ExportStrategy strategy) { prepareExport(); String content = strategy.format(data); validateContent(content); writeToFile(content); completeExport(); } protected void prepareExport() { System.out.println("Preparing export..."); } protected abstract void validateContent(String content); protected void writeToFile(String content) { System.out.println("Writing to file: " + content); } protected void completeExport() { System.out.println("Export completed"); } } @FunctionalInterface public interface ExportStrategy { String format(List<?> data); } public class CsvExportStrategy implements ExportStrategy { @Override public String format(List<?> data) { return data.stream() .map(Object::toString) .collect(Collectors.joining(",")); } }

七、Spring Batch模式

7.1 ItemReader

public interface ItemReader<T> { T read(); } public abstract class AbstractItemReader<T> implements ItemReader<T> { @Override public final T read() { T item = doRead(); if (item != null) { log("Read item: " + item); } return item; } protected abstract T doRead(); protected void log(String message) { System.out.println("[Reader] " + message); } }

7.2 ItemProcessor

@FunctionalInterface public interface ItemProcessor<I, O> { O process(I item) throws Exception; } public class ValidationProcessor<I> implements ItemProcessor<I, I> { private final List<ItemValidator<I>> validators; @Override public I process(I item) throws Exception { for (ItemValidator<I> validator : validators) { validator.validate(item); } return item; } }

八、最佳实践

8.1 使用final修饰模板方法

public abstract class BaseTemplate { public final void execute() { // 防止被子类重写 step1(); step2(); step3(); } protected abstract void step1(); protected abstract void step2(); protected abstract void step3(); }

8.2 钩子方法

public abstract class HookTemplate { public final void process() { beforeProcess(); doProcess(); afterProcess(); } protected void beforeProcess() { // 空实现,钩子 } protected abstract void doProcess(); protected void afterProcess() { // 默认实现,钩子 System.out.println("Cleanup..."); } }

总结

模板方法模式通过将不变的部分封装在父类,变化的部分延迟到子类实现,达到了代码复用的目的。Spring的JdbcTemplate、RestTemplate等是这一模式的经典应用。在实际开发中,可以结合Callback接口和Lambda表达式,使模板方法模式更加灵活和简洁。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 1:11:06

三步掌握Zotero中文文献管理:茉莉花插件完整使用指南

三步掌握Zotero中文文献管理&#xff1a;茉莉花插件完整使用指南 【免费下载链接】jasminum A Zotero add-on to retrive CNKI meta data. 一个简单的Zotero 插件&#xff0c;用于识别中文元数据 项目地址: https://gitcode.com/gh_mirrors/ja/jasminum 还在为Zotero处理…

作者头像 李华
网站建设 2026/5/20 1:09:07

C语言迭代器模式:实现算法与数据结构的解耦

1. 从“指针”到“迭代器”&#xff1a;为什么我们需要一个更通用的“导航器”&#xff1f;在嵌入式或者C语言开发的日常里&#xff0c;我们最熟悉的“导航”工具莫过于指针。想遍历一个数组&#xff1f;用一个int *p从头指到尾就行。想操作链表&#xff1f;用一个指向struct n…

作者头像 李华
网站建设 2026/5/20 1:07:27

耐高温PPS塑料厂家宏裕塑胶:专业品质与服务体验

导读&#xff1a;对于制造业企业而言&#xff0c;选择一家具备专业品质与服务体验的耐高温PPS塑料厂家&#xff0c;往往意味着供应链的稳定、产品性能的提升以及长期合作的保障。在华南工程塑料领域&#xff0c;宏裕塑胶以其“源头直采技术赋能”的模式&#xff0c;逐步成长为细…

作者头像 李华
网站建设 2026/5/20 1:03:14

Path of Building装备制作终极指南:从混沌石到毕业装

Path of Building装备制作终极指南&#xff1a;从混沌石到毕业装 【免费下载链接】PathOfBuilding Offline build planner for Path of Exile. 项目地址: https://gitcode.com/gh_mirrors/pat/PathOfBuilding 你是否曾经在《流放之路》中投入大量通货制作装备&#xff0…

作者头像 李华