Dificilmente preciso discutir por que a reutilização do código é benéfica. A reutilização do código geralmente torna o desenvolvimento do programa mais rápido e reduz bugs. Depois que um código é encapsulado e reutilizado, é necessário verificar um pedaço de código muito pequeno para garantir a correção do programa. Se você precisar apenas abrir e fechar a conexão do banco de dados em um local em todo o aplicativo, é muito mais fácil garantir que a conexão seja normal. Mas tenho certeza que você já conhece tudo isso.
Existem dois tipos de códigos de reutilização, que eu chamo de tipos de reutilização:
O primeiro tipo é a reutilização funcional, que é o tipo mais comum de reutilização. Este também é um tipo de domínio para a maioria dos desenvolvedores. Ou seja, reutilize um conjunto de instruções subsequentes para executar alguma operação.
O segundo tipo é a reutilização do contexto, ou seja, diferentes funções ou códigos de operação são encapsulados entre os mesmos contextos, e o mesmo contexto é encapsulado do código de reutilização (o contexto aqui se refere a uma série das mesmas instruções de operação). Embora esteja se tornando mais popular na reversão do controle, não é comum. Além disso, a reutilização do contexto não é explicitamente descrita, portanto, não é usada pelo sistema como a reutilização funcional. Espero que você mude depois de ler este artigo.
Reutilização da função
A reutilização funcional é o tipo mais comum de reutilização. É a reutilização de um conjunto de instruções que executam algum tipo de operação. Os dois métodos a seguir são ler dados do banco de dados:
Lista pública readAllUsers () {conexão de conexão = null; String sql = "selecione * dos usuários"; Listar usuários = new ArrayList (); tente {conexão = OpenConnection (); Declaração de estatamento preparado = conexão.Preparestatement (SQL); ResultSet Result = declaration.executeQuery (); while (resultado.Next ()) {// Código de reutilização Usuário do usuário = new User (); user.setName (resultado.getString ("nome")); user.setEmail (resultado.getString ("email")); usuários.add (usuário); // Código de reutilização final} resultado.close (); declaration.close (); devolver usuários; } catch (sqLexception e) {// ignore por enquanto} finalmente {// ignore por enquanto}} list public list READUSERSOFSTATUS (status da string) {conexão de conexão = null; String sql = "selecione * dos usuários onde status =?"; Listar usuários = new ArrayList (); tente {conexão = OpenConnection (); Declaração de estatamento preparado = conexão.Preparestatement (SQL); declaração.SetString (1, status); ResultSet Result = declaration.executeQuery (); while (resultado.Next ()) {// Código de reutilização Usuário do usuário = new User (); user.setName (resultado.getString ("nome")); user.setEmail (resultado.getString ("email")); usuários.add (usuário); // Código de reutilização final} resultado.close (); declaration.close (); devolver usuários; } catch (sqlexception e) {// ignore por enquanto} finalmente {// ignore por enquanto}}Para desenvolvedores experientes, pode ser possível descobrir o código reutilizável em breve. O local onde o "código de reutilização" é comentado no código acima é o mesmo, portanto, a reutilização pode ser encapsulada. Essas são as operações que leem os registros do usuário em instâncias de usuário. Essas linhas de código podem ser encapsuladas em seus próprios métodos, por exemplo:
// encapsula a mesma operação no método readUser Private User ReadUser (resultado Resultados) lança SQLEXCECCIONE {Usuário do usuário = new User (); user.setName (resultado.getString ("nome")); user.setEmail (resultado.getString ("email")); usuários.add (usuário); devolver usuário; }Agora, ligue para o método readUser () nos dois métodos acima (o exemplo a seguir mostra apenas o primeiro método):
Lista pública readAllUsers () {conexão de conexão = null; String sql = "selecione * dos usuários"; Listar usuários = new ArrayList (); tente {conexão = OpenConnection (); Declaração de estatamento preparado = conexão.Preparestatement (SQL); ResultSet Result = declaration.executeQuery (); while (result.Next ()) {usuários.add (readUser (resultado))} resultado.close (); declaration.close (); devolver usuários; } catch (sqlexception e) {// ignore por enquanto} finalmente {// ignore por enquanto}}O método readUser () também pode ser oculto em sua própria classe usando o modificador privado.
O exposto acima é sobre a reutilização de funções. A reutilização funcional é encapsular um conjunto de instruções que executam operações específicas por meio de métodos ou classes para alcançar o objetivo da reutilização.
Operações parametrizadas
Às vezes, você deseja reutilizar um conjunto de operações, mas essas operações não são exatamente as mesmas em qualquer lugar que você usa. Por exemplo, os métodos ReadAllUsers () e ReadUsersOfStatus () abrem uma conexão, preparam uma instrução, executam -a e percorrem o conjunto de resultados. A única diferença é que o ReadUsersOfStatus () exige que um parâmetro seja definido no preparado. Podemos encapsular todas as operações em um método readUserList (). Como mostrado abaixo:
Lista privada ReadUSerList (String SQL, String [] parâmetros) {Connection Connection = null; Listar usuários = new ArrayList (); tente {conexão = OpenConnection (); Declaração de estatamento preparado = conexão.Preparestatement (SQL); for (int i = 0; i <parâmetros.length; i ++) {declaration.SetString (i, parâmetros [i]); } ResultSet Result = declaration.executeQuery (); while (result.Next ()) {usuários.add (readUser (resultado))} resultado.close (); declaration.close (); devolver usuários; } catch (sqlexception e) {// ignore por enquanto} finalmente {// ignore por enquanto}} Agora, chamamos readUserList(...) de readAllUsers() e readUsersOfStatus() e fornecemos diferentes parâmetros de operação:
Lista pública readAllUsers () {return readUserList ("Selecione * From Usuários", new String [] {});} Lista pública ReadUsersWithStatus (String status) {return readUserList ("Selecione * FROM USUERS", new String [] {status};}}Acredito que você pode encontrar outras maneiras melhores de implementar funções de reutilização e parametrizá -las para facilitar o uso.
Reutilização de contexto
A reutilização do contexto é um pouco diferente da reutilização de recursos. A reutilização do contexto é a reutilização de uma série de instruções, e várias operações são sempre realizadas entre essas instruções. Em outras palavras, reutilize declarações antes e depois de vários comportamentos. Portanto, a reutilização do contexto geralmente leva a uma inversão de classes de estilo de controle. A reutilização do contexto é uma maneira muito eficaz de reutilizar o manuseio de exceções, o gerenciamento do ciclo de vida e o ciclo de vida da transação, a iteração e o desligamento de fluxo e muitos outros contextos operacionais comuns.
Aqui estão dois métodos que são feitos com o InputStream:
public void PrintStream (inputStream inputStream) lança ioexception {if (inputStream == null) return; Ioexception exceção = nulo; tente {int caractere = inputStream.read (); while (caractere! = -1) {System.out.print ((char) caractere); // caracteres diferentes = inputStream.read (); }} finalmente {tente {inputStream.close (); } catch (ioexception e) {if (excepção == null) tiro e; }}} public string readstream (inputStream inputStream) lança ioexception {stringbuffer buffer = new stringBuffer (); // diferente se (inputStream == null) retorna; Ioexception exceção = nulo; tente {int caractere = inputStream.read (); while (caractere! = -1) {buffer.append ((char) caractere); // caracteres diferentes = inputStream.read (); } retornar buffer.toString (); // diferente} finalmente {tente {inputStream.close (); } catch (ioexception e) {if (excepção == null) tiro e; }}}Os dois métodos são diferentes da operação de fluxo. Mas o contexto em torno dessas operações é o mesmo. O código de contexto itera e fecha o InputStream. Além das diferenças no uso de marcas de comentários, o código acima é o seu código de contexto.
Como mostrado acima, o contexto envolve o manuseio de exceção e garante que o fluxo seja fechado corretamente após a iteração. Escrever tal tratamento de erros e código de liberação de recursos repetidamente é complicado e propenso a erros. O manuseio de erros e o manuseio de conexão corretos são mais complexos nas transações JDBC. Obviamente, é mais fácil escrever código uma vez e reutilizá -lo em qualquer lugar.
Felizmente, o método de encapsular o contexto é simples. Crie uma classe de contexto e coloque o contexto público nela. No uso do contexto, diferentes instruções de operação são abstraídas na interface de operação e, em seguida, cada operação é encapsulada na classe que implementa a interface de operação (chamada de classe de operação aqui). Você só precisa inserir uma instância da classe de operação no contexto. Isso pode ser feito passando uma instância da classe de operação como um parâmetro para o construtor do objeto de contexto ou passando uma instância da classe de operação como um parâmetro para o método de execução específico do contexto.
A seguir, mostra como separar o exemplo acima em contexto e interface operacional. StreamProcessor (interface de operação) é passado como um parâmetro para o método processStream () do StreamProcessorContext.
// interface do plug -in de processamento de fluxo interface pública StreamProcessor {public void Process (int input);} // PROCESSÃO DE STRAMENT CLASS Public class StreamProcessorContext {// Instanciam a interface de operação de streamProcessor (IFPURANSTROCUSTEMPROPT (IFPUTROUST (INPUTROUSTERCURSTEMCROURCS) e serve como um parâmetro de reprodução iftream (inputream inputStream, streamProcessorception) e serve). Ioexception exceção = nulo; tente {int caractere = inputStream.read (); while (caractere! = -1) {processor.process (caractere); caractere = inputStream.read (); }} finalmente {tente {inputStream.close (); } catch (ioexception e) {if (excepção == null) tiro e; Exceção de lançar; }}}}Agora você pode usar a classe StreamProcessorContext para imprimir o conteúdo do fluxo, como o exemplo a seguir:
FileInputStream inputStream = new FileInputStream ("myFile"); // Exemplo da operação através da implementação anônima da subclasse da interface StreamProcessor new StreamProcessorContext (). ProcessStream (inputStream, new StreamProcessor () {public void) (Int input) {System.out.out.out.Int.Int, (s);Ou leia o conteúdo do fluxo de entrada como este e adicione -o a uma sequência de caracteres:
public class StreamToStringReader implementa StreamProcessor {Private StringBuffer buffer = new StringBuffer (); public stringbuffer getBuffer () {return this.Buffer; } public void Process (int input) {this.buffer.append ((char) entrada); }} FileInputStream inputStream = new FileInputStream ("MyFile"); StreamToStringReader Reader = new StreamToStringReader (); new StreamProcessorContext (). ProcessStream (InputStream, Reader); // Faça algo com a entrada do stream.reader.getBer ();Como você pode ver, faça qualquer coisa com o fluxo inserindo uma implementação de interface de fluxo de fluxo diferente. Depois que o StreamProcessSorContext estiver totalmente implementado, você nunca terá problemas com fluxos não isolados.
A reutilização do contexto é muito poderosa e pode ser usada em muitos outros ambientes fora do processamento de fluxos. Um caso de uso óbvio é lidar com conexões e transações de banco de dados corretamente ( open - process - commit()/rollback() - close() ). Outros casos de uso são o processamento do canal de nio e a sincronização de threads em seções críticas ( lock() - access shared resource - unlock() ). Também pode converter exceções verificadas da API em exceções desmarcadas.
Quando você procura código adequado para reutilização de contexto em seu projeto, procure os seguintes modos de operação:
Quando você encontra esse padrão, as operações regulares antes e depois podem alcançar a reutilização do contexto.
Contexto como método de modelo
Às vezes, você deseja ter vários pontos de plug -in no contexto. Se o contexto consistir em muitas etapas menores e você deseja que cada etapa do contexto seja personalizável, poderá implementar o contexto como um método de modelo. O método de modelo é um padrão de design do GOF. Basicamente, o método de modelo divide um algoritmo ou protocolo em uma série de etapas. Um método de modelo é geralmente implementado como uma única classe base e fornece um método para cada etapa em um algoritmo ou protocolo. Para personalizar qualquer etapa, basta criar uma classe que estenda a classe base do método do modelo e substitua o método da etapa que você deseja personalizar.
O exemplo a seguir é um JDBCContext implementado como um método de modelo. As subclasses podem substituir a abertura e o fechamento das conexões para fornecer comportamento personalizado. O método ProcessRecord (resultado do resultado do resultado) deve sempre ser substituído porque é abstrato. Este método fornece operações que não estão no contexto e são diferentes em diferentes casos usando o JDBCContext. Este exemplo não é um JDBCContext perfeito. É usado apenas para demonstrar como usar os métodos de modelo ao implementar o contexto.
classe public abstrata JDBCContext {DataSource DataSource = null; // O construtor sem parâmetros pode ser usado para subclasses sem o DataSource para obter a conexão public jdbcContext () {} public jdbcContext (DataSource DataSource) {this.DataSource = DataSource; } conexão protegida OpenConnection () lança sqLexception {return DataSource.getConnection (); } Protegido Void CloseConnection (conexão de conexão) lança SqLexception {Connection.close (); } // ProcessRecord (Método Resultado Resultado) Protectado ProcessRecord (resultado Resultado) lança SQLEXCECCETION; public void Execute (String sql, objeto [] parâmetros) lança SqLexception {Connection Connection = null; Declaração de estatamento preparado = nulo; ResultSet Result = NULL; tente {conexão = OpenConnection (); declaração = conexão.Preparestatement (SQL); for (int i = 0; i <parâmetros.length; i ++) {declaration.setObject (i, parâmetros [i]); } resultado = declaration.executeQuery (); while (result.Next ()) {processRecord (resultado); }} finalmente {if (resultado! = null) {try {result.close (); } catch (sqLexception e) { / * ignore * /}} if (declaration! = null) {try {declaration.close (); } catch (sqLexception e) { / * ignore * /}} if (declaration! = null) {try {declaration.close (); } catch (sqLexception e) { / * ignore * /}} if (conexão! = null) {closeConnection (conexão); }}}}Esta é uma subclasse que estende o JDBCContext para ler a lista de usuários:
classe pública ReadUsers estende JDBCContext {List Users = new ArrayList (); public readusers (DataSource DataSource) {super (DataSource); } public list getUsers () {return this.Users; } Protected void processRecord (resultado do resultado) {usuário user = new User (); user.setName (resultado.getString ("nome")); user.setEmail (resultado.getString ("email")); usuários.add (usuário); }}Aqui está como usar a classe ReadUsers:
READUSERS READUSERS = NOVO READUSERS (DataSource); readusers.execute ("Selecione * FROM USUERS", novo objeto [0]); listar usuários = readusers.getUsers (); Se a classe ReadUsers precisar obter uma conexão do pool de conexões e liberá -la de volta ao pool de conexões após o uso, você poderá inserir a conexão substituindo openConnection() e closeConnection(Connection connection) .
Observe como reescrever o código de operação Inserir através do método. A subclasse do JDBCContext substitui o método ProcessRecord para fornecer processamento especial de registros. No exemplo do StreamContext, o código de operação é encapsulado em um objeto separado e é fornecido como um parâmetro de método. O objeto que implementa a interface de operação PROCESSOR STREAM é passada como um parâmetro para o método ProcessStreamContext Class processStream(...) .
Você pode usar as duas técnicas ao implementar o contexto. A classe JDBCContext pode passar os objetos ConnectionOpener e ConnectCloser que implementam a interface de operação como parâmetros para o método Execute ou como parâmetros do construtor. Pessoalmente, prefiro usar objetos de operação separados e interfaces de operação por dois motivos. Primeiro, facilita o teste de unidade apenas o código de operação; Segundo, torna o código de operação reutilizável em vários contextos. Obviamente, o código de operação também pode ser usado em vários locais do código, mas isso é apenas uma vantagem. Afinal, aqui estamos apenas tentando reutilizar o contexto, não reutilizar as operações.
Conclusão
Agora você viu duas maneiras diferentes de reutilizar o código. Reutilização clássica de recursos e reutilização menos comum de contexto. Esperançosamente, a reutilização do contexto será tão comum quanto a reutilização do recurso. A reutilização do contexto é uma maneira muito útil de abstrair o código dos detalhes subjacentes de uma API (como JDBC, IO ou API NIO, etc.). Especialmente se a API contiver recursos que precisam ser gerenciados (dentro e fechar, obter e retornar etc.).
API de persistência/ORM, o Sr.Persister usa a reutilização do contexto para alcançar a conexão automática e o gerenciamento do ciclo de vida da transação. Dessa forma, o usuário nunca precisará se preocupar em abrir ou fechar a conexão corretamente ou cometer ou reverter a transação. O Sr.Persister fornece contexto no qual os usuários podem inserir suas operações. Esses contextos são responsáveis por abrir, fechar, cometer e reverter.
A estrutura popular da primavera contém muita reutilização de contexto. Por exemplo, abstração JDBC Springs. Os desenvolvedores da primavera o usam como uma "reversão de controle". Este não é o único tipo de inversão de controle usado pelo Spring Frameworks. O recurso principal da primavera é as fábricas de feijão de injeção de dependência ou "contextos de aplicativos". A injeção de dependência é outro tipo de inversão de controle.
O exposto acima é a reutilização de função e contexto do código Java que o editor apresentou a você. Espero que seja útil para você. Se você tiver alguma dúvida, deixe -me uma mensagem e o editor responderá a você a tempo. Muito obrigado pelo seu apoio ao site wulin.com!