コードの再利用が有益である理由を議論する必要はほとんどありません。通常、コードの再利用により、プログラムの開発が速くなり、バグが減少します。コードがカプセル化されて再利用されると、プログラムの正確性を確保するために、非常に小さなコードをチェックする必要があります。アプリケーション全体で1つの場所でデータベース接続を開閉するだけで閉じる必要がある場合、接続が正常であることを確認する方がはるかに簡単です。しかし、私はあなたがすでにこのすべてを知っていると確信しています。
再利用コードには2つのタイプがありますが、これを再利用タイプと呼びます。
最初のタイプは機能的な再利用であり、これは最も一般的なタイプの再利用です。これは、ほとんどの開発者にとっても一種の習得です。つまり、操作を実行するために、その後の一連の指示を再利用します。
2番目のタイプはコンテキストの再利用です。つまり、異なる関数または操作コードが同じコンテキスト間でカプセル化され、同じコンテキストが再利用コードとカプセル化されます(ここでのコンテキストは、同じ操作指示のシリーズを指します)。コントロールの逆転で人気が高まっていますが、一般的ではありません。さらに、コンテキストの再利用は明示的に記述されていないため、機能的な再利用などのシステムでは使用されません。この記事を読んだ後に変わることを願っています。
関数の再利用
機能的な再利用は、最も一般的なタイプの再利用です。何らかの操作を実行する一連の指示の再利用です。次の2つの方法は、データベースからデータを読むことです。
public List readallusers(){connection connection = null;文字列sql = "select * from users"; list users = new arrayList(); try {connection = openconnection(); preatedStatementステートメント= connection.preparestatement(sql); resultet result = statement.executequery(); while(result.next()){//コードユーザー= new user(); user.setname(result.getString( "name")); user.setemail(result.getString( "email")); users.add(user); //再利用コード} result.close(); Statement.Close();ユーザーを返します。 } catch(sqlexception e){//今のところ無視}最後に{//今のところ無視}} public list readusersofstatus(string status){connection connection = null; string sql = "select * from users where status =?"; list users = new arrayList(); try {connection = openconnection(); preatedStatementステートメント= connection.preparestatement(sql); Statement.setString(1、status); resultet result = statement.executequery(); while(result.next()){//コードユーザー= new user(); user.setname(result.getString( "name")); user.setemail(result.getString( "email")); users.add(user); //再利用コード} result.close(); Statement.Close();ユーザーを返します。 } catch(sqlexception e){//今のところ無視}最後に{//今のところ無視}}}経験豊富な開発者の場合、再利用可能なコードをすぐに発見することが可能かもしれません。上記のコードで「再利用コード」がコメントされる場所は同じであるため、再利用をカプセル化できます。これらは、ユーザーレコードをユーザーインスタンスに読み取る操作です。これらのコード行は、たとえば、独自の方法にカプセル化できます。
//同じ操作をReaduser Methodにカプセル化しますプライベートユーザーリードューザー(結果の結果)スローsqlexception {user user = new user(); user.setname(result.getString( "name")); user.setemail(result.getString( "email")); users.add(user);ユーザーを返します。 }次に、上記の2つの方法でReaduser()メソッドを呼び出します(次の例は、最初の方法のみを示しています):
public List readallusers(){connection connection = null;文字列sql = "select * from users"; list users = new arrayList(); try {connection = openconnection(); preatedStatementステートメント= connection.preparestatement(sql); resultet result = statement.executequery(); while(result.next()){users.add(readuser(result))} result.close(); Statement.Close();ユーザーを返します。 } catch(sqlexception e){//今のところ無視}最後に{//今のところ無視}}}Readuser()メソッドは、Modifier Privateを使用して独自のクラスに非表示にすることもできます。
上記は、機能の再利用に関するものです。機能的な再利用とは、再利用の目的を達成するために、方法またはクラスを通じて特定の操作を実行する一連の命令をカプセル化することです。
パラメーター化された操作
操作のセットを再利用したい場合もありますが、これらの操作は使用する場所ではまったく同じではありません。たとえば、readallusers()およびreadusersofstatus()メソッドの両方が接続を開き、ステートメントを準備し、実行し、結果セットをループします。唯一の違いは、ReadusersofStatus()では、prepedStatementでパラメーターを設定する必要があることです。すべての操作をReadUserList()メソッドにカプセル化できます。以下に示すように:
プライベートリストReadUserList(String SQL、String []パラメーター){接続接続= null; list users = new arrayList(); try {connection = openconnection(); preatedStatementステートメント= connection.preparestatement(sql); for(int i = 0; i <parameters.length; i ++){statement.setString(i、parameters [i]); } resultSet result = statement.executequery(); while(result.next()){users.add(readuser(result))} result.close(); Statement.Close();ユーザーを返します。 } catch(sqlexception e){//今のところ無視}最後に{//今のところ無視}}}次にreadUserList(...)メソッドをreadAllUsers()およびreadUsersOfStatus()から呼び出し、異なる操作パラメーターを提供します。
public list readallusers(){return readuserlist( "select * from users"、new string [] {});} public list readuserswithstatus(string status){return readuserlist( "select * fromユーザー"、new String [] {status});}再利用関数を実装し、パラメーター化して使いやすくするための他のより良い方法を見つけることができると思います。
コンテキストの再利用
コンテキストの再利用は、機能の再利用とはわずかに異なります。コンテキストの再利用は、一連の指示の再利用であり、これらの指示の間で常にさまざまな操作が実行されます。言い換えれば、さまざまな行動の前後の声明を再利用します。したがって、コンテキストの再利用は、多くの場合、制御スタイルのクラスの反転につながります。コンテキストの再利用は、例外処理、接続およびトランザクションのライフサイクル管理、フローイテレーションとシャットダウン、およびその他の多くの一般的な運用コンテキストを再利用する非常に効果的な方法です。
入力ストリームで行われる2つの方法を次に示します。
public void printStream(inputstream inputstream)IoException {if(inputstream == null)return; ioException例外= null; try {int character = inputstream.read(); while(character!= -1){system.out.print((char)character); //異なる文字= inputstream.read(); }}最後に{try {inputstream.close(); } catch(ioException e){if(exception == null)throw e; }}} public string readstream(inputstream inputstream)throws ioexception {stringbuffer buffer = new StringBuffer(); //異なるif(inputstream == null)return; ioException例外= null; try {int character = inputstream.read(); while(character!= -1){buffer.append(((char)character); //異なる文字= inputstream.read(); } return buffer.toString(); //違う}最後に{try {inputstream.close(); } catch(ioException e){if(exception == null)throw e; }}}2つの方法は、フロー操作とは異なります。しかし、これらの操作に関するコンテキストは同じです。コンテキストコードは、inputStreamを反復し、閉じます。コメントマークの使用の違いに加えて、上記のコードはコンテキストコードです。
上記のように、コンテキストには例外処理が含まれ、反復後にストリームが正しく閉じられるようにします。このようなエラー処理とリソースリリースコードを何度も書き込むことは、面倒でエラーが発生しやすいです。 JDBCトランザクションでは、エラー処理と正しい接続処理がより複雑です。コードを一度書いてどこでも再利用する方が明らかに簡単です。
幸いなことに、コンテキストをカプセル化する方法は簡単です。コンテキストクラスを作成し、パブリックコンテキストをそれに入れます。コンテキストの使用では、異なる操作命令が操作インターフェイスに抽出され、各操作がクラスにカプセル化され、操作インターフェイスを実装します(操作クラスはこちらの操作クラスと呼ばれます)。操作クラスのインスタンスをコンテキストに挿入するだけです。操作クラスのインスタンスをパラメーターとしてコンテキストオブジェクトのコンストラクターに渡すか、操作クラスのインスタンスをパラメーターとしてコンテキストの特定の実行方法に渡すことによって実行できます。
以下は、上記の例をコンテキストと運用インターフェイスに分離する方法を示しています。 StreamProcessor(操作インターフェイス)は、StreamProcessorContextのProcessStream()メソッドのパラメーターとして渡されます。
//プラグインインターフェイスパブリックインターフェイスStreamProcessor {public void Process(int input);} //ストリーム処理コンテキシコンテストクラスパブリッククラスStreamProcessorContext {// StreamProcessor操作インターフェイスをインスタンス化し、パラメーターPublic ProcessStream(inputStream inputStream、Streamprocessor Processor)を使用します。 ioException例外= null; try {int character = inputstream.read(); while(文字!= -1){processor.process(文字);文字= inputstream.read(); }}最後に{try {inputstream.close(); } catch(ioException e){if(exception == null)throw e;例外をスローします。 }}}}これで、StreamProcessorContextクラスを使用して、次の例のようにストリームコンテンツを印刷できます。
FileInputStream inputStream = new FileInputStream( "myFile"); // StreamProcessorインターフェイスの匿名のサブクラス実装による操作の例new StreamProcessorContext()。processStream()。
または、このような入力ストリームコンテンツを読み、文字シーケンスに追加します。
パブリッククラスStreamToStringReaderは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(Reader); // stream.reader.getBuffer()ご覧のとおり、別のStreamProcessorインターフェイスの実装を挿入して、ストリームで何でも実行します。 StreamProcessorContextが完全に実装されると、閉鎖されていないストリームに問題はありません。
コンテキストの再利用は非常に強力であり、ストリーム処理以外の多くの環境で使用できます。明らかなユースケースは、データベースの接続とトランザクションを正しく処理することです( open - process - commit()/rollback() - close() )。その他のユースケースは、重要なセクションでのNIOチャネル処理とスレッドの同期です( lock() - access shared resource - unlock() )。また、APIからチェックされていない例外にチェックされた例外を変換することもできます。
プロジェクトでコンテキストの再利用に適したコードを探すときは、次の操作モードを探します。
そのようなパターンを見つけた場合、前後の通常の操作はコンテキストの再利用を達成する場合があります。
テンプレートメソッドとしてのコンテキスト
コンテキストに複数のプラグインポイントが必要な場合があります。コンテキストが多くの小さな手順で構成され、コンテキストの各ステップをカスタマイズ可能にする場合は、テンプレートメソッドとしてコンテキストを実装できます。テンプレートメソッドはGOFデザインパターンです。基本的に、テンプレートメソッドは、アルゴリズムまたはプロトコルを一連のステップに分割します。テンプレートメソッドは通常、単一のベースクラスとして実装され、アルゴリズムまたはプロトコルの各ステップのメソッドを提供します。任意のステップをカスタマイズするには、テンプレートメソッドベースクラスを拡張するクラスを作成し、カスタマイズするステップのメソッドをオーバーライドするだけです。
次の例は、テンプレートメソッドとして実装されたJDBCContextです。サブクラスは、接続の開閉をオーバーライドして、カスタム動作を提供することができます。 ProcessRecord(結果の結果)メソッドは、抽象的であるため、常にオーバーライドする必要があります。この方法は、コンテキストにない操作を提供し、JDBCContextを使用して異なる場合に異なる場合があります。この例は、完璧なJDBCContextではありません。コンテキストを実装するときにテンプレートメソッドを使用する方法を示すためにのみ使用されます。
パブリックアブストラクトクラスjdbccontext {dataSource dataSource = null; //パラメーターのないコンストラクターをデータソースなしのサブクラスに使用して、接続を取得するためにパブリックjdbccontext(){} public jdbccontext(dataSource dataSource){this.datasource = dataSource; }保護された接続openconnection()throws sqlexception {return dataSource.getConnection(); }保護されたvoid closeconnection(接続接続)sqlexception {connection.close(); } // processRecord(resultSet result)メソッド保護抽象プロセスレコード(results result)スローSqlexception; public void execute(string sql、object []パラメーター)をsqlexception {connection connection = null; preatedStatementステートメント= null; resultet result = null; try {connection = openconnection();ステートメント= connection.preparestatement(sql); for(int i = 0; i <parameters.length; i ++){statement.setObject(i、parameters [i]); } result = statement.executequery(); while(result.next()){processRecord(result); }}最後に{if(result!= null){try {result.close(); } catch(sqlexception e){ / * adignore * /}} if(statement!= null){try {statement.close(); } catch(sqlexception e){ / * adignore * /}} if(statement!= null){try {statement.close(); } catch(sqlexception e){ / * Inivare * /}} if(connection!= null){closeconnection(connection); }}}}これは、JDBCContextを拡張してユーザーリストを読み取るサブクラスです。
パブリッククラスの読み取り機はjdbccontextを拡張します{list users = new ArrayList();パブリックリードューサ(DataSource DataSource){super(dataSource); } public list getusers(){return this.users; } protected void ProcessRecord(resultset result){user user = new user(); user.setname(result.getString( "name")); user.setemail(result.getString( "email")); users.add(user); }}次に、読み取り機のクラスの使用方法です。
Readusers readusers = new Readusers(dataSource); Readusers.execute( "select * from users"、new object [0]); list users = readusers.getusers();
Readusersクラスが接続プールから接続を取得し、使用後に接続プールに戻す必要がある場合は、 openConnection()およびcloseConnection(Connection connection)メソッドをオーバーライドして接続を挿入できます。
メソッドを介して挿入操作コードを書き換える方法に注意してください。 JDBCContextのサブクラスは、特別なレコード処理を提供するプロセスレコードメソッドをオーバーライドします。 StreamContextの例では、操作コードは別のオブジェクトにカプセル化され、メソッドパラメーターとして提供されます。操作インターフェイスStreamProcessorを実装するオブジェクトは、ProcessStreamContextクラスprocessStream(...)メソッドのパラメーターとして渡されます。
コンテキストを実装するときに両方の手法を使用できます。 JDBCContextクラスは、操作インターフェイスを実行メソッドのパラメーターとして、またはコンストラクターのパラメーターとして実装するConnectionOpenerおよびConnectionCloserオブジェクトを渡すことができます。個人的には、2つの理由で個別の操作オブジェクトと操作インターフェイスを使用することを好みます。まず、操作コードのみを単独でテストしやすくなります。第二に、複数のコンテキストで操作コードを再利用可能にします。もちろん、操作コードはコード内の複数の場所でも使用できますが、これは単なる利点です。結局のところ、ここでは、操作を再利用するのではなく、コンテキストを再利用しようとしています。
結論
これで、コードを再利用する2つの異なる方法が見られました。古典的な機能の再利用とあまり一般的でないコンテキストの再利用。うまくいけば、コンテキストの再利用が機能の再利用と同じくらい一般的です。コンテキストの再利用は、APIの基礎となる詳細(JDBC、IO、NIO APIなど)からコードを抽象化する非常に便利な方法です。特に、APIに管理する必要があるリソースが含まれている場合(オンと閉じて、取得して戻るなど)。
Persistence/orm API、Mr。Persisterはコンテキストの再利用を使用して、自動接続とトランザクションのライフサイクル管理を実現します。このようにして、ユーザーは、接続を正しく開閉したり閉じたり、トランザクションをコミットまたはロールバックすることを心配する必要はありません。 Mr.Persisterは、ユーザーが操作を挿入できるコンテキストを提供します。これらのコンテキストは、開閉、閉鎖、コミット、ロールバックを担当します。
人気のスプリングフレームワークには、多くのコンテキストの再利用が含まれています。たとえば、Springs JDBC抽象化。スプリング開発者は、それを「コントロール反転」として使用します。これは、Spring Frameworksが使用する唯一の制御反転タイプではありません。スプリングの中核的な特徴は、依存関係噴射豆工場または「アプリケーションコンテキスト」です。依存性噴射は、制御反転の別のタイプです。
上記は、編集者が紹介したJavaコードの関数とコンテキストの再利用です。それがあなたに役立つことを願っています。ご質問がある場合は、メッセージを残してください。編集者は時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!