20210720のJavaに関する記事は5件です。

【Java発展学習14-15日目】設計原則とGoFデザインパターン、モジュールシステム

6つの設計原則 分類 設計原則 内容 コード記述 DRY(Don't Repeat Yourself) 繰り返さない PIE(Program Intently and Expressively) 意味・意図の明確化 クラス設計 SRP(Single Responsibility Principle) 単一責任原則 OCP(Open-Closed Principle) 開放閉鎖原則 クラス間連携 SDP(Stable Dependencies Principle) 安定依存原則 ADP(Acyclic Dependencies Principle) 非循環依存原則 PIE PIEでは、「コメント文を取り除いても可読性の高いコード」を目指す。 具体的には、以下の3つの手法をとる。 変数名で役割・目的を表す マジックナンバーをfinal定数で命名 制御構造の深い処理への命名 SRP 参考: 発展学習12日目(メトリクス) SRPでは、「修正時の再テスト範囲が関連部分のみに限定されるクラス」を目指す。 ただし、必要以上の分割はかえって可読性や機能性が落ちるため、WMCを基準としてクラスの分割・統合を決定する。 OCP OCPでは、「拡張に対して開放的であり、変更に対して閉鎖的なクラス」を目指す。 具体的には、「継承によって拡張可能であり、継承元クラスが変更不要なクラス」を指す。 SDP SDPでは、「上位クラスやUIから遠いクラスなどの、修正頻度が低い安定的なクラスに依存する」ことを目指す。 ADP ADPでは、「クラス間の循環・相互依存による修正の連鎖を抑える」ことを目指す。 GoF(Gang of Four)デザインパターン 参考1: GoFのデザインパターン 参考2: デザインパターン 参考3: デザインパターン入門 参考4: ぼくにもわかるデザインパターン 数多く存在する設計原則を採用したGoFのデザインパターンは、以下の通り。 分類 デザインパターン 内容 生成 Abstract Factory 共通部品群の生成 Builder 実体化の複雑なインスタンスの生成 Factory Method 部品のインスタンス生成のみ具象ファクトリに委託 Prototype インスタンスの複製 Singleton 単一インスタンスの生成 構造 Adapter 関連のない2つのクラスの結び付け Bridge 機能の「追加」と「実装」を両立 Composite 階層構造の簡素化 Decorator 間接的継承による機能拡張 Facade ファサードによる処理の集約 Flyweight インスタンスの共有 Proxy 代理オブジェクトによる処理 振る舞い Chain of Responsibility 再帰的処理の実行 Command 処理の(クラス)オブジェクト化による処理内容の保持 Interpreter 文法規則クラスによる構文解析 Iterator 集合の構成要素に対するシーケンシャルアクセス Mediator 結合度の低いオブジェクト間の結び付け Memento 状態の記録・読み込み Observer 状態遷移時に処理を実行 State 状態(を表すSingletonオブジェクト)に応じた分岐処理の実行 Strategy 多様なアルゴリズムの実現 Template Method 不確定処理と確定処理の融合 Visitor 互いに利用し合う処理の実行 Abstract Factory 抽象ファクトリの抽象メソッドの引数に応じた具象ファクトリの生成 具象ファクトリによる共通具象物の生成 具象物に応じたメソッドの呼び出し Builder 具象ビルダを保持する監督者の生成 監督者が保持する具象ビルダによる具象物の整形 Factory Method 具象ファクトリの生成 具象ファクトリによる具象物の生成 具象物に応じたメソッドの呼び出し Prototype Cloneableインタフェースを継承するプロトタイプインタフェースの定義 プロトタイプインタフェースの実装クラス(プロトタイプクラス)に応じたclone()メソッドの呼び出し プロトタイプクラスに応じたメソッドの呼び出し Singleton コンストラクタをprivateで定義 private staticなフィールドでオブジェクトを生成 private staticなフィールドの返却 Adapter 抽象クラスまたはインタフェースの実装クラス(アダプタクラス)のオブジェクトを生成 アダプタクラスを通じた他クラスのメソッドの呼び出し Bridge 具象「機能実装」クラスを保持する抽象「機能追加」クラスの生成 具象「機能実装」クラスを保持する具象「機能追加」クラスの生成 具象「機能追加」クラスを通じたメソッドの呼び出し Composite 共通の抽象クラスをもつ継承クラスオブジェクトの生成 継承クラスを通じたメソッドの呼び出し Decorator 共通の抽象クラスをもつ継承クラスオブジェクトの生成 継承クラスを通じたメソッドの呼び出し ※ Compositeとの違いは、共通の抽象クラスをもつ別の派生関係にあるクラスのメソッドを呼び出す点にある。 Facade 利用クラスを束ねるファサードクラスを通じたメソッドの呼び出し Flyweight ファクトリクラスにSingletonパターンを適用 具体物をMapプールに格納しておき、適宜プール内で呼び出して再利用 Proxy 共通の抽象主体クラスを継承するプロキシクラス・具象主体クラスの生成※プロキシクラスは具象主体クラスを内部的に保持 プロキシクラス内部の具象主体クラスがnull(未生成)であれば代理処理を行い、具象主体クラスを生成 プロキシクラス内部の具象主体クラスが存在すれば具象主体クラスのメソッドの呼び出し Chain of Responsibility 抽象ハンドラクラス型のフィールド(ハンドラフィールド)を保持する具体ハンドラクラスの生成 ハンドラフィールドに具体ハンドラクラスをセット ハンドラフィールドを再帰的に利用するメソッドの呼び出し Command 共通の抽象コマンドクラスを継承する具象コマンドクラスの生成 具象コマンドクラスに応じたメソッドの呼び出し Interpreter 規則と一対一対応したクラスを利用した構文解析 Iterator コレクションの生成 コレクションを保持するイテレータクラスの生成 イテレータクラスを通じたコレクション内の構成要素への順次アクセス Mediator 全ての具象同僚クラスをコレクションで保持する具象仲介者クラスの生成 同一の具象仲介者クラスを保持する具象同僚クラスの生成 具象同僚クラスを通じた、具象仲介者クラスのメソッドの呼び出し Memento ある時点でのフィールド情報を保持するメメントクラスの生成 メメントオブジェクトをコレクションに格納し、任意の時点での記録を反映 Observer 具象観察対象クラスのフィールド情報を変更 抽象観察対象クラスからオブザーバクラスのメソッドを呼び出し State Singletonパターンを採用した状態クラスオブジェクトの生成 状態に応じた分岐処理の実行 Strategy 具象戦略クラスを保持する文脈クラスの生成 文脈クラスを通じた具象戦略クラスのメソッドの呼び出し Template Method 抽象クラスでprotectedな抽象メソッドを含む、finalな処理の流れを記述 具象クラスで抽象メソッドの処理を記述 Visitor 具象受入者クラスで、引数に訪問者クラスをとる訪問者クラスのメソッドの呼び出し 具象訪問者クラスで、引数に受入者クラスをとる受入者クラスのメソッドの呼び出し モジュール定義 モジュールに関する定義は、JARファイル直下に配置するmodule-info.javaファイルに記述する。 パッケージのアクセス制御 パッケージごとの外部アクセス制御はexports文またはopens文で記述する。 アクセス制御子 通常アクセス リフレクション exports o o opens x o 依存モジュールの指定 モジュールが外部モジュールに依存する場合、requires文で外部モジュールを指定する。 サンプルコード module-info.java module jp.advance.b150005 { exports <公開パッケージ>; opens <リフレクションのみ許可する限定公開パッケージ>; requires <依存モジュール>; } モジュールパスを指定したJARファイルの利用 # モジュールパスを指定したコンパイル % javac -p <モジュールパス> <ソースファイル> # モジュールパスを指定したクラスファイルの実行 % java -p <モジュールパス> <メインクラスのFQCN> 用語集 用語 内容 マジックナンバー(magic number) コード中に登場する、意味が不明瞭な数値リテラル。 ソフトウェアフレームワーク(software framework) 独自定義したクラスを呼び出すクラス群。 モジュールシステム(module system) JARファイルの公開にあたって、公開するパッケージを制御する仕組み。 モジュールパス(module path) モジュールシステムを利用するJARファイルの格納先ディレクトリパス。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java発展学習14日目】設計原則とGoFデザインパターン、モジュールシステム

6つの設計原則 分類 設計原則 内容 コード記述 DRY(Don't Repeat Yourself) 繰り返さない PIE(Program Intently and Expressively) 意味・意図の明確化 クラス設計 SRP(Single Responsibility Principle) 単一責任原則 OCP(Open-Closed Principle) 開放閉鎖原則 クラス間連携 SDP(Stable Dependencies Principle) 安定依存原則 ADP(Acyclic Dependencies Principle) 非循環依存原則 PIE PIEでは、「コメント文を取り除いても可読性の高いコード」を目指す。 具体的には、以下の3つの手法をとる。 変数名で役割・目的を表す マジックナンバーをfinal定数で命名 制御構造の深い処理への命名 SRP 参考: 発展学習12日目(メトリクス) SRPでは、「修正時の再テスト範囲が関連部分のみに限定されるクラス」を目指す。 ただし、必要以上の分割はかえって可読性や機能性が落ちるため、WMCを基準としてクラスの分割・統合を決定する。 OCP OCPでは、「拡張に対して開放的であり、変更に対して閉鎖的なクラス」を目指す。 具体的には、「継承によって拡張可能であり、継承元クラスが変更不要なクラス」を指す。 SDP SDPでは、「上位クラスやUIから遠いクラスなどの、修正頻度が低い安定的なクラスに依存する」ことを目指す。 ADP ADPでは、「クラス間の循環・相互依存による修正の連鎖を抑える」ことを目指す。 GoF(Gang of Four)デザインパターン 参考1: GoFのデザインパターン 参考2: デザインパターン 参考3: デザインパターン入門 参考4: ぼくにもわかるデザインパターン 数多く存在する設計原則を採用したGoFのデザインパターンは、以下の通り。 分類 デザインパターン 内容 生成 Abstract Factory 共通部品群の生成 Builder 実体化の複雑なインスタンスの生成 Factory Method 部品のインスタンス生成のみ具象ファクトリに委託 Prototype インスタンスの複製 Singleton 単一インスタンスの生成 構造 Adapter 関連のない2つのクラスの結び付け Bridge 機能の「追加」と「実装」を両立 Composite 階層構造の簡素化 Decorator 間接的継承による機能拡張 Facade ファサードによる処理の集約 Flyweight インスタンスの共有 Proxy 代理オブジェクトによる処理 振る舞い Chain of Responsibility 再帰的処理の実行 Command 処理の(クラス)オブジェクト化による処理内容の保持 Interpreter 文法規則クラスによる構文解析 Iterator 集合の構成要素に対するシーケンシャルアクセス Mediator 結合度の低いオブジェクト間の結び付け Memento 状態の記録・読み込み Observer 状態遷移時に処理を実行 State 状態(を表すSingletonオブジェクト)に応じた分岐処理の実行 Strategy 多様なアルゴリズムの実現 Template Method 不確定処理と確定処理の融合 Visitor 互いに利用し合う処理の実行 Abstract Factory 抽象ファクトリの抽象メソッドの引数に応じた具象ファクトリの生成 具象ファクトリによる共通具象物の生成 具象物に応じたメソッドの呼び出し Builder 具象ビルダを保持する監督者の生成 監督者が保持する具象ビルダによる具象物の整形 Factory Method 具象ファクトリの生成 具象ファクトリによる具象物の生成 具象物に応じたメソッドの呼び出し Prototype Cloneableインタフェースを継承するプロトタイプインタフェースの定義 プロトタイプインタフェースの実装クラス(プロトタイプクラス)に応じたclone()メソッドの呼び出し プロトタイプクラスに応じたメソッドの呼び出し Singleton コンストラクタをprivateで定義 private staticなフィールドでオブジェクトを生成 private staticなフィールドの返却 Adapter 抽象クラスまたはインタフェースの実装クラス(アダプタクラス)のオブジェクトを生成 アダプタクラスを通じた他クラスのメソッドの呼び出し Bridge 具象「機能実装」クラスを保持する抽象「機能追加」クラスの生成 具象「機能実装」クラスを保持する具象「機能追加」クラスの生成 具象「機能追加」クラスを通じたメソッドの呼び出し Composite 共通の抽象クラスをもつ継承クラスオブジェクトの生成 継承クラスを通じたメソッドの呼び出し Decorator 共通の抽象クラスをもつ継承クラスオブジェクトの生成 継承クラスを通じたメソッドの呼び出し ※ Compositeとの違いは、共通の抽象クラスをもつ別の派生関係にあるクラスのメソッドを呼び出す点にある。 Facade 利用クラスを束ねるファサードクラスを通じたメソッドの呼び出し Flyweight ファクトリクラスにSingletonパターンを適用 具体物をMapプールに格納しておき、適宜プール内で呼び出して再利用 Proxy 共通の抽象主体クラスを継承するプロキシクラス・具象主体クラスの生成※プロキシクラスは具象主体クラスを内部的に保持 プロキシクラス内部の具象主体クラスがnull(未生成)であれば代理処理を行い、具象主体クラスを生成 プロキシクラス内部の具象主体クラスが存在すれば具象主体クラスのメソッドの呼び出し Chain of Responsibility 抽象ハンドラクラス型のフィールド(ハンドラフィールド)を保持する具体ハンドラクラスの生成 ハンドラフィールドに具体ハンドラクラスをセット ハンドラフィールドを再帰的に利用するメソッドの呼び出し Command 共通の抽象コマンドクラスを継承する具象コマンドクラスの生成 具象コマンドクラスに応じたメソッドの呼び出し Interpreter 規則と一対一対応したクラスを利用した構文解析 Iterator コレクションの生成 コレクションを保持するイテレータクラスの生成 イテレータクラスを通じたコレクション内の構成要素への順次アクセス Mediator 全ての具象同僚クラスをコレクションで保持する具象仲介者クラスの生成 同一の具象仲介者クラスを保持する具象同僚クラスの生成 具象同僚クラスを通じた、具象仲介者クラスのメソッドの呼び出し Memento ある時点でのフィールド情報を保持するメメントクラスの生成 メメントオブジェクトをコレクションに格納し、任意の時点での記録を反映 Observer 具象観察対象クラスのフィールド情報を変更 抽象観察対象クラスからオブザーバクラスのメソッドを呼び出し State Singletonパターンを採用した状態クラスオブジェクトの生成 状態に応じた分岐処理の実行 Strategy 具象戦略クラスを保持する文脈クラスの生成 文脈クラスを通じた具象戦略クラスのメソッドの呼び出し Template Method 抽象クラスでprotectedな抽象メソッドを含む、finalな処理の流れを記述 具象クラスで抽象メソッドの処理を記述 Visitor 具象受入者クラスで、引数に訪問者クラスをとる訪問者クラスのメソッドの呼び出し 具象訪問者クラスで、引数に受入者クラスをとる受入者クラスのメソッドの呼び出し モジュール定義 モジュールに関する定義は、JARファイル直下に配置するmodule-info.javaファイルに記述する。 パッケージのアクセス制御 パッケージごとの外部アクセス制御はexports文またはopens文で記述する。 アクセス制御子 通常アクセス リフレクション exports o o opens x o 依存モジュールの指定 モジュールが外部モジュールに依存する場合、requires文で外部モジュールを指定する。 サンプルコード module-info.java module jp.advance.b150005 { exports <公開パッケージ>; opens <リフレクションのみ許可する限定公開パッケージ>; requires <依存モジュール>; } モジュールパスを指定したJARファイルの利用 # モジュールパスを指定したコンパイル % javac -p <モジュールパス> <ソースファイル> # モジュールパスを指定したクラスファイルの実行 % java -p <モジュールパス> <メインクラスのFQCN> 用語集 用語 内容 マジックナンバー(magic number) コード中に登場する、意味が不明瞭な数値リテラル。 ソフトウェアフレームワーク(software framework) 独自定義したクラスを呼び出すクラス群。 モジュールシステム(module system) JARファイルの公開にあたって、公開するパッケージを制御する仕組み。 モジュールパス(module path) モジュールシステムを利用するJARファイルの格納先ディレクトリパス。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Couchbase Java SDK解説:分散トランザクション実例

はじめに Couchbase SDKを使った、Javaプログラミングにおけるトランザクションの扱いを具体的なAPIコールに即して解説します。 本記事の関連情報として以下をご参照ください。 Couchbase Java SDK解説:分散トランザクションの内部メカニズム Couchbase Java SDK解説:分散トランザクション〜エラー処理を理解する Couchbase Java SDK解説:分散トランザクションプログラミング入門 ドキュメントへのK/Vアクセス ドキュメントの取得 ドキュメントを取得するには、getとgetOptionalの2つのメソッドがあります。 まず、getOptionalについて見てみます。このメソッドでは、指定されたIDにマッチするドキュメントが存在しない場合、Optional.empty()が返されます。 transactions.run((ctx) -> { String docId = "a-doc"; Optional<TransactionGetResult> docOpt = ctx.getOptional(collection, docId); if(doc.isPresent()) { // ドキュメントに対する処理 } }); まず、getについて見てみます。 transactions.run((ctx) -> { String docId = "a-doc"; TransactionGetResult doc = ctx.get(collection, docId); }); getでは、開発者はドキュメントが存在するかどうかを確認する必要はありません。指定されたIDにマッチするドキュメントが存在しない場合、TransactionFailed例外とともに、処理が失敗します。 ドキュメントの挿入 以下は、ドキュメント挿入のコードスニペットです(トランザクションプログラミングに固有のことではありませんが、指定したIDのドキュメントが既に存在している場合は、処理は失敗します)。 非同期API: transactions.reactive().run((ctx) -> { return ctx.insert(collection.reactive(), "docId", JsonObject.create()).then(); }).block(); 同期API: transaction.run((ctx)-> { String docId = "docId"; ctx.insert(collection、docId、JsonObject.create()); }); トランザクション中で挿入されたドキュメントは、そのトランザクション内で取得することが可能です(これは、想定通りの挙動であるはずです)。例えば以下のコードは成功します。 transactions.run((ctx) -> { String docId = "docId"; ctx.insert(collection, docId, JsonObject.create()); Optional<TransactionGetResult> doc = ctx.getOptional(collection, docId); assert (doc.isPresent()); }); ドキュメントの置換 トランザクション内で、ドキュメントを置換するには、最初にctx.get()をコールする必要があります。これは、そのドキュメントが別のトランザクションに関与しないようにするために必要となります。(そのドキュメントが別のトランザクションに関与している場合、トランザクションは適切にこれを処理します。通常、これまでに行われたことをロールバックし、ラムダを再試行します。) 同期API: transactions.run((ctx) -> { TransactionGetResult anotherDoc = ctx.get(collection, "anotherDoc"); JsonObject content = anotherDoc.contentAs(JsonObject.class); content.put("transactions", "are awesome"); ctx.replace(anotherDoc, content); }); 非同期API: transactions.reactive().run((ctx) -> { return ctx.get(collection.reactive(), "anotherDoc").flatMap(doc -> { JsonObject content = doc.contentAs(JsonObject.class); content.put("transactions", "are awesome"); return ctx.replace(doc, content); }).then(ctx.commit()); }); ドキュメントの削除 置換と同様、ドキュメントを削除するには、最初にctx.get()をコールする必要があります。 非同期API: transactions.reactive().run((ctx) -> { return ctx.get(collection.reactive(), "anotherDoc").flatMap(doc -> ctx.remove(doc)); }); 同期API: transactions.run((ctx) -> { TransactionGetResult anotherDoc = ctx.get(collection, "anotherDoc"); ctx.remove(anotherDoc); }); 包括的な例 ここでは、マルチプレイヤーオンラインゲームをシミュレートした例を紹介します。この例では、プレイヤーが、モンスターにダメージを与えます。プレーヤーとモンスターの情報は個々のドキュメントとして管理されており、トランザクション内で、ヒットポイント、経験値などの情報の更新が行われます。 (実際には、このようなゲームの挙動を実現する際に、トランザクションのためのパフォーマンスコストを支払う代わりに、リスクが低く、影響が限定されているという判断のもと、非トランザクションプログラミングを選択することも十分に考えられます。) public void playerHitsMonster(int damage, String playerId, String monsterId) { Transactions transactions = getTransactions(); try { transactions.run((ctx) -> { TransactionGetResult monsterDoc = ctx.get(collection, monsterId); TransactionGetResult playerDoc = ctx.get(collection, playerId); int monsterHitpoints = monsterDoc.contentAs(JsonObject.class).getInt("hitpoints"); int monsterNewHitpoints = monsterHitpoints - damage; if (monsterNewHitpoints <= 0) { // ヒットポイントが0以下になったため、モンスターが殺されます。 // 以下では、(例示としての簡便のため)ドキュメントを削除していますが、 // 実際的には、フラグの値を変更することが考えられます。 ctx.remove(monsterDoc); // プレイヤーはモンスターを殺すことによって経験値を獲得します int experienceForKillingMonster = monsterDoc.contentAs(JsonObject.class) .getInt("experienceWhenKilled"); int playerExperience = playerDoc.contentAs(JsonObject.class).getInt("experience"); int playerNewExperience = playerExperience + experienceForKillingMonster; int playerNewLevel = calculateLevelForExperience(playerNewExperience); JsonObject playerContent = playerDoc.contentAs(JsonObject.class); playerContent.put("experience", playerNewExperience); playerContent.put("level", playerNewLevel); ctx.replace(playerDoc, playerContent); } else { // モンスターはダメージを受けていますが、まだ生きています JsonObject monsterContent = monsterDoc.contentAs(JsonObject.class); monsterContent.put("hitpoints", monsterNewHitpoints); ctx.replace(monsterDoc, monsterContent); } }); } catch (TransactionFailed e) { // 何らかの理由でトランザクションが失敗しました。 // トランザクション中の変更は全て、ロールバックされます。 } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Couchbase Java SDK解説:分散トランザクション API解説および包括的な利用例

はじめに Couchbase SDKを使った、Javaプログラミングにおけるトランザクションの扱いを具体的なAPIコールに即して解説します。 本記事の関連情報として以下をご参照ください。 Couchbase Java SDK解説:分散トランザクションの内部メカニズム Couchbase Java SDK解説:分散トランザクション〜エラー処理を理解する Couchbase Java SDK解説:分散トランザクションプログラミング入門 ドキュメントへのK/Vアクセス ドキュメントの取得 ドキュメントを取得するには、getとgetOptionalの2つのメソッドがあります。 まず、getOptionalについて見てみます。このメソッドでは、指定されたIDにマッチするドキュメントが存在しない場合、Optional.empty()が返されます。 transactions.run((ctx) -> { String docId = "a-doc"; Optional<TransactionGetResult> docOpt = ctx.getOptional(collection, docId); if(doc.isPresent()) { // ドキュメントに対する処理 } }); まず、getについて見てみます。 transactions.run((ctx) -> { String docId = "a-doc"; TransactionGetResult doc = ctx.get(collection, docId); }); getでは、開発者はドキュメントが存在するかどうかを確認する必要はありません。指定されたIDにマッチするドキュメントが存在しない場合、TransactionFailed例外とともに、処理が失敗します。 ドキュメントの挿入 以下は、ドキュメント挿入のコードスニペットです(トランザクションプログラミングに固有のことではありませんが、指定したIDのドキュメントが既に存在している場合は、処理は失敗します)。 非同期API: transactions.reactive().run((ctx) -> { return ctx.insert(collection.reactive(), "docId", JsonObject.create()).then(); }).block(); 同期API: transaction.run((ctx)-> { String docId = "docId"; ctx.insert(collection、docId、JsonObject.create()); }); トランザクション中で挿入されたドキュメントは、そのトランザクション内で取得することが可能です(これは、想定通りの挙動であるはずです)。例えば以下のコードは成功します。 transactions.run((ctx) -> { String docId = "docId"; ctx.insert(collection, docId, JsonObject.create()); Optional<TransactionGetResult> doc = ctx.getOptional(collection, docId); assert (doc.isPresent()); }); ドキュメントの置換 トランザクション内で、ドキュメントを置換するには、最初にctx.get()をコールする必要があります。これは、そのドキュメントが別のトランザクションに関与しないようにするために必要となります。(そのドキュメントが別のトランザクションに関与している場合、トランザクションは適切にこれを処理します。通常、これまでに行われたことをロールバックし、ラムダを再試行します。) 同期API: transactions.run((ctx) -> { TransactionGetResult anotherDoc = ctx.get(collection, "anotherDoc"); JsonObject content = anotherDoc.contentAs(JsonObject.class); content.put("transactions", "are awesome"); ctx.replace(anotherDoc, content); }); 非同期API: transactions.reactive().run((ctx) -> { return ctx.get(collection.reactive(), "anotherDoc").flatMap(doc -> { JsonObject content = doc.contentAs(JsonObject.class); content.put("transactions", "are awesome"); return ctx.replace(doc, content); }).then(ctx.commit()); }); ドキュメントの削除 置換と同様、ドキュメントを削除するには、最初にctx.get()をコールする必要があります。 非同期API: transactions.reactive().run((ctx) -> { return ctx.get(collection.reactive(), "anotherDoc").flatMap(doc -> ctx.remove(doc)); }); 同期API: transactions.run((ctx) -> { TransactionGetResult anotherDoc = ctx.get(collection, "anotherDoc"); ctx.remove(anotherDoc); }); 包括的な利用例 ここでは、マルチプレイヤーオンラインゲームをシミュレートした例を紹介します。この例では、プレイヤーが、モンスターにダメージを与えます。プレーヤーとモンスターの情報は個々のドキュメントとして管理されており、トランザクション内で、ヒットポイント、経験値などの情報の更新が行われます。 (実際には、このようなゲームの挙動を実現する際に、トランザクションのためのパフォーマンスコストを支払う代わりに、リスクが低く、影響が限定されているという判断のもと、非トランザクションプログラミングを選択することも十分に考えられます。) public void playerHitsMonster(int damage, String playerId, String monsterId) { Transactions transactions = getTransactions(); try { transactions.run((ctx) -> { TransactionGetResult monsterDoc = ctx.get(collection, monsterId); TransactionGetResult playerDoc = ctx.get(collection, playerId); int monsterHitpoints = monsterDoc.contentAs(JsonObject.class).getInt("hitpoints"); int monsterNewHitpoints = monsterHitpoints - damage; if (monsterNewHitpoints <= 0) { // ヒットポイントが0以下になったため、モンスターが殺されます。 // 以下では、(例示としての簡便のため)ドキュメントを削除していますが、 // 実際的には、フラグの値を変更することが考えられます。 ctx.remove(monsterDoc); // プレイヤーはモンスターを殺すことによって経験値を獲得します int experienceForKillingMonster = monsterDoc.contentAs(JsonObject.class) .getInt("experienceWhenKilled"); int playerExperience = playerDoc.contentAs(JsonObject.class).getInt("experience"); int playerNewExperience = playerExperience + experienceForKillingMonster; int playerNewLevel = calculateLevelForExperience(playerNewExperience); JsonObject playerContent = playerDoc.contentAs(JsonObject.class); playerContent.put("experience", playerNewExperience); playerContent.put("level", playerNewLevel); ctx.replace(playerDoc, playerContent); } else { // モンスターはダメージを受けていますが、まだ生きています JsonObject monsterContent = monsterDoc.contentAs(JsonObject.class); monsterContent.put("hitpoints", monsterNewHitpoints); ctx.replace(monsterDoc, monsterContent); } }); } catch (TransactionFailed e) { // 何らかの理由でトランザクションが失敗しました。 // トランザクション中の変更は全て、ロールバックされます。 } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

"指定されたコンパイラー準拠は x.y ですが、JRE zz が使用されています"の解消

Eclipse でプロジェクトを作ると 指定されたコンパイラー準拠は 1.5 ですが、JRE 11 が使用されています みたいなWarningが出ることがある。 これはまんま、このプロジェクトでコンパイル/ビルド用に指定したjavacのバージョンが1.5になっているが、実際に環境にインストールされているJavaのバージョンはJRE 11ですよと言っている。 実際問題、Java 1.5 でコンパイルしたコードは Java 11 でも Deprecated になった API さえ利用していなければほとんどの場合動作すると思う。けれど Warning が出たままだと気持ち悪いし、古い API を間違って使ってしまうのも嫌なので、実行環境の JRE のバージョンとビルド用の javac のバージョンを合わせる方法について以下に記載する。 プロジェクトのJRE システム・ライブラリー~を右クリック、プロパティ 実行環境のバージョンに、先ほどのエラーでJRE 11 が使用されていますと記載されていたのでJRE 11を選択して適用。 こんな感じで Warning が消える。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む