现在可以像下面示例一样使用StreamProcessorContext类打印出流内容:
FileInputStream inputStream = new FileInputStream("myFile"); // 通过实现 StreamProcessor 接口的匿名子类传递操作实例 new StreamProcessorContext() .processStream(inputStream, new StreamProcessor(){ public void process(int input){ System.out.print((char) input); } });或者像下面这样读取输入流内容并添加到一个字符序列中:
public class StreamToStringReader implements StreamProcessor{ private StringBuffer buffer = new StringBuffer(); public StringBuffer getBuffer(){ return this.buffer; } public void process(int input){ this.buffer.append((char) input); } } FileInputStream inputStream = new FileInputStream("myFile"); StreamToStringReader reader = new StreamToStringReader(); new StreamProcessorContext().processStream(inputStream, reader); // do something with input from stream. reader.getBuffer();正如你所看到的,通过插入不同的StreamProcessor接口实现来对流做任何操作。一旦StreamProcessorContext被完全实现,你将永远不会有关于未关闭流的困扰。
上下文重用非常强大,可以在流处理之外的许多其他环境中使用。一个明显的用例是正确处理数据库连接和事务(open - process - commit()/rollback() - close())。其他用例是 NIO 通道处理和临界区中的线程同步(lock() - access shared resource - unlock())。它也能将API的已检查异常转换为未检查异常。
当你在自己的项目中查找适合上下文重用的代码时,请查找以下操作模式:
常规操作之前(general action before)
特殊操作(special action)
常规操作之后(general action after)
当你找到这样的模式时,前后的常规操作就可能实现上下文重用。
上下文作为模板方法有时候你会希望在上下文中有多个插件点。如果上下文由许多较小的步骤组成,并且你希望上下文的每个步骤都可以自定义,则可以将上下文实现为模板方法。模板方法是一种 GOF 设计模式。基本上,模板方法将算法或协议分成一系列步骤。一个模板方法通常作为一个单一的基类实现,并为算法或协议中的每一步提供一个方法。要自定义任何步骤,只需创建一个扩展模板方法基类的类,并重写要自定义的步骤的方法。
下面的示例是作为模板方法实现的 JdbcContext。子类可以重写连接的打开和关闭, 以提供自定义行为。必须始终重写processRecord(ResultSet result)方法, 因为它是抽象的。此方法提供不属于上下文的操作,在使用JdbcContext的不同情况下的操作都不相同。这个例子不是一个完美的JdbcContext。它仅用于演示在实现上下文时如何使用模板方法。
public abstract class JdbcContext { DataSource dataSource = null; // 无参数的构造函数可以用于子类不需要 DataSource 来获取连接 public JdbcContext() { } public JdbcContext(DataSource dataSource){ this.dataSource = dataSource; } protected Connection openConnection() throws SQLException{ return dataSource.getConnection(); } protected void closeConnection(Connection connection) throws SQLException{ connection.close(); } // 必须始终重写 processRecord(ResultSet result) 方法 protected abstract processRecord(ResultSet result) throws SQLException ; public void execute(String sql, Object[] parameters) throws SQLException { Connection connection = null; PreparedStatement statement = null; ResultSet result = null; try{ connection = openConnection(); statement = connection.prepareStatement(sql); for (int i=0; i < parameters.length; i++){ statement.setObject(i, parameters[i]); } result = statement.executeQuery(); while(result.next()){ processRecord(result); } } finally { if(result != null){ try{ result.close(); } catch(SQLException e) { /* ignore */ } } if(statement != null){ try{ statement.close(); } catch(SQLException e) { /* ignore */ } } if(connection != null){ closeConnection(connection); } } } }