Javaにおけるダーティフラグパターン:変更追跡によるパフォーマンス最適化
別名
- 変更追跡
- 変更済みフラグ
ダーティフラグデザインパターンの意図
ダーティフラグデザインパターンは、オブジェクトの状態が変化した(「ダーティ」)か、変化していない(「クリーン」)かを追跡するブール値フラグを保持することで、不要な計算やリソースを大量に消費する操作を回避するために使用されます。このフラグが設定されている場合、更新された状態を反映するために、データの再計算やリフレッシュなどの特定の操作を再度実行する必要があることを示します。
実例を用いたダーティフラグパターンの詳細な説明
実際の例
どの本が貸し出され、返却されたかを追跡する電子カタログシステムを備えた図書館を想像してみてください。各本の記録には、「ダーティフラグ」があり、本が貸し出されたり返却されたりするたびにマークされます。毎日終わりに、図書館員は「ダーティ」とマークされた記録のみを確認して、図書館内のすべての本をチェックするのではなく、実際の在庫を更新します。このシステムは、状態が変更されたアイテムのみに焦点を当てることで、毎日の在庫チェックに必要な労力と時間を大幅に削減します。これは、ダーティフラグデザインパターンが必要な場合にのみリソース集約的な操作を実行することで、リソース集約的な操作を最小限に抑える方法に類似しています。
平易な言葉で
ダーティフラグデザインパターンは、オブジェクトの状態が変化し、更新が必要な場合を追跡するフラグを使用することで、不要な操作を最小限に抑えます。
ウィキペディアによると
ダーティビットまたは変更ビットは、コンピュータメモリのブロックに関連付けられたビットであり、対応するメモリブロックが変更されたかどうかを示します。ダーティビットは、プロセッサがこのメモリに書き込む(変更する)ときに設定されます。このビットは、関連付けられたメモリブロックが変更され、まだストレージに保存されていないことを示します。メモリブロックを置き換える場合、対応するダーティビットをチェックして、ブロックを置き換える前にセカンダリメモリに書き戻す必要があるかどうか、または単に削除できるかどうかを確認します。ダーティビットは、CPUキャッシュやオペレーティングシステムのページ置換アルゴリズムで使用されます。
Javaにおけるダーティフラグパターンのプログラム例
DataFetcher
クラスは、ファイルからデータをフェッチする役割を担います。これには、最後のフェッチ以降にファイルのデータが変更されたかどうかを示すダーティフラグがあります。
public class DataFetcher {
private long lastFetched;
private boolean isDirty = true;
// Other properties and methods...
}
DataFetcher
クラスには、データをフェッチする前にダーティフラグをチェックするフェッチメソッドがあります。フラグがtrueの場合、ファイルからデータをフェッチし、フラグをfalseに設定します。フラグがfalseの場合、以前にフェッチしたデータを返します。
public List<String> fetch() {
if (!isDirty) {
return data;
}
data = fetchFromDatabase();
isDirty = false;
return data;
}
World
クラスはDataFetcher
を使用してデータをフェッチします。これには、DataFetcher
のfetch
メソッドを呼び出すfetch
メソッドがあります。
public class World {
private final DataFetcher fetcher = new DataFetcher();
public List<String> fetch() {
return fetcher.fetch();
}
}
App
クラスには、ダーティフラグパターンの使用を実証するmain
メソッドが含まれています。World
オブジェクトを作成し、ループでそこからデータをフェッチします。World
オブジェクトはDataFetcher
を使用してデータをフェッチし、DataFetcher
はダーティフラグがtrueの場合にのみファイルからデータをフェッチします。
@Slf4j
public class App {
public void run() {
final var executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
final World world = new World();
@Override
public void run() {
var countries = world.fetch();
LOGGER.info("Our world currently has the following countries:-");
countries.stream().map(country -> "\t" + country).forEach(LOGGER::info);
}
}, 0, 15, TimeUnit.SECONDS); // Run at every 15 seconds.
}
public static void main(String[] args) {
var app = new App();
app.run();
}
}
プログラムの出力は次のとおりです
12:06:02.612 [pool-1-thread-1] INFO com.iluwatar.dirtyflag.DataFetcher -- world.txt is dirty! Re-fetching file content...
12:06:02.615 [pool-1-thread-1] INFO com.iluwatar.dirtyflag.App -- Our world currently has the following countries:-
12:06:02.616 [pool-1-thread-1] INFO com.iluwatar.dirtyflag.App -- UNITED_KINGDOM
12:06:02.616 [pool-1-thread-1] INFO com.iluwatar.dirtyflag.App -- MALAYSIA
12:06:02.616 [pool-1-thread-1] INFO com.iluwatar.dirtyflag.App -- UNITED_STATES
Javaでダーティフラグパターンを使用するタイミング
- 操作がリソース集約的であり、特定の変更が発生した後にのみ必要な場合。
- 変更の確認が操作自体を実行するよりも大幅に安価なシナリオでは、費用対効果を高めます。
- オブジェクトが更新にコストがかかり、更新が頻繁ではない状態を維持するシステム内で、パフォーマンス効率を向上させます。
ダーティフラグパターンのJavaチュートリアル
Javaにおけるダーティフラグパターンの実際の応用例
- 変更されたシーンの一部のみを更新するためのグラフィックレンダリングエンジンで、効率的なレンダリングのためにダーティフラグパターンを利用します。
- 部分的なページレンダリングやキャッシュ戦略のためのWebアプリケーション。
- 書き込み操作を最小限に抑えるためにデータセットの変更を追跡するためのデータベースアプリケーション。効率的なデータベース管理を保証します。
ダーティフラグパターンのメリットとトレードオフ
メリット
- 不要な操作を回避することで、計算とリソースのオーバーヘッドを削減し、パフォーマンスの向上につながります。
- 操作がコストがかかり、変更が頻繁ではないシステムでパフォーマンスを大幅に向上させ、システムの最適化を促進します。
- 特定操作の実行時期に関する意思決定プロセスを簡素化し、効果的なリソース割り当てを支援します。
トレードオフ
- システムのステート管理の責任を追加することで複雑さを導入します。
- フラグが状態の変化を正確に反映し、古くなったデータや不正確なデータを回避するために、フラグを注意深く管理する必要があります。
- フラグのリセットが不適切なことに関連するバグのリスクが潜在的に増加し、システムの信頼性に影響を与えます。
関連するJavaデザインパターン
- オブザーバー:ダーティフラグが設定またはクリアされたときに、関係者に通知するために連携して使用できます。
- メメント:オブジェクトの以前の状態を保存するのに役立ちます。ダーティフラグのロジックと連携して、クリーンな状態に戻すことができます。
- コマンド:コマンドを実行時にダーティフラグを設定して、注意が必要な状態の変化を示すことができます。