Javaにおけるメメントパターン:アンドゥ操作のためのオブジェクト状態の保持
別名
- スナップショット
- トークン
メメントデザインパターンの意図
Javaにおけるメメントデザインパターンは、開発者がカプセル化を侵害することなくオブジェクトの内部状態をキャプチャして復元することを可能にします。
メメントパターンの詳細な説明と実際の例
実際の例
テキストエディタアプリケーションは、Javaにおけるメメントデザインパターンを利用して、アンドゥとリドゥの機能を有効にすることができます。変更が行われるたびにドキュメントの現在の状態をメメントとしてキャプチャすることで、アプリケーションはドキュメントを前の状態に簡単に復元できます。スナップショットは履歴リストに保存されます。ユーザーがアンドゥボタンをクリックすると、エディターは最新のメメントに保存された状態にドキュメントを復元します。このプロセスにより、ユーザーはエディターの内部データ構造を公開したり変更したりすることなく、ドキュメントの以前のバージョンに戻ることができます。
平易な言葉で言うと
メメントパターンは、オブジェクトの内部状態をキャプチャし、任意の時点でオブジェクトを保存および復元することを容易にします。
Wikipediaによると
メメントパターンは、オブジェクトを以前の状態に復元する(ロールバックによるアンドゥ)機能を提供するソフトウェアデザインパターンです。
Javaにおけるメメントパターンのプログラム例
私たちの占星術アプリケーションでは、メメントパターンを使用して星オブジェクトの状態をキャプチャおよび復元します。各状態はメメントとして保存され、必要に応じて前の状態に戻すことができます。
まず、私たちが処理できる星のタイプを定義しましょう。
public enum StarType {
SUN("sun"),
RED_GIANT("red giant"),
WHITE_DWARF("white dwarf"),
SUPERNOVA("supernova"),
DEAD("dead star");
// ...
}
次に、本質に直接飛び込みましょう。これは、操作する必要があるメメントとともに、Star
クラスです。特に、getMemento
メソッドとsetMemento
メソッドに注意してください。
public interface StarMemento {
}
public class Star {
private StarType type;
private int ageYears;
private int massTons;
public Star(StarType startType, int startAge, int startMass) {
this.type = startType;
this.ageYears = startAge;
this.massTons = startMass;
}
public void timePasses() {
ageYears *= 2;
massTons *= 8;
switch (type) {
case RED_GIANT -> type = StarType.WHITE_DWARF;
case SUN -> type = StarType.RED_GIANT;
case SUPERNOVA -> type = StarType.DEAD;
case WHITE_DWARF -> type = StarType.SUPERNOVA;
case DEAD -> {
ageYears *= 2;
massTons = 0;
}
default -> {
}
}
}
StarMemento getMemento() {
var state = new StarMementoInternal();
state.setAgeYears(ageYears);
state.setMassTons(massTons);
state.setType(type);
return state;
}
void setMemento(StarMemento memento) {
var state = (StarMementoInternal) memento;
this.type = state.getType();
this.ageYears = state.getAgeYears();
this.massTons = state.getMassTons();
}
@Override
public String toString() {
return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons);
}
private static class StarMementoInternal implements StarMemento {
private StarType type;
private int ageYears;
private int massTons;
// setters and getters ->
// ...
}
}
そして最後に、メメントを使用して星の状態を保存および復元する方法を次に示します。
public static void main(String[] args) {
var states = new Stack<StarMemento>();
var star = new Star(StarType.SUN, 10000000, 500000);
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
LOGGER.info(star.toString());
while (!states.isEmpty()) {
star.setMemento(states.pop());
LOGGER.info(star.toString());
}
}
プログラム出力
14:09:15.878 [main] INFO com.iluwatar.memento.App -- sun age: 10000000 years mass: 500000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- red giant age: 20000000 years mass: 4000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- white dwarf age: 40000000 years mass: 32000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- supernova age: 80000000 years mass: 256000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- dead star age: 160000000 years mass: 2048000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- supernova age: 80000000 years mass: 256000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- white dwarf age: 40000000 years mass: 32000000 tons
14:09:15.881 [main] INFO com.iluwatar.memento.App -- red giant age: 20000000 years mass: 4000000 tons
14:09:15.881 [main] INFO com.iluwatar.memento.App -- sun age: 10000000 years mass: 500000 tons
Javaでメメントパターンを使用する場合
メメントパターンを使用する場合
- Javaでオブジェクトの状態をキャプチャし、内部構造を公開せずに後で復元する必要がある場合。これは、カプセル化を維持し、オブジェクト状態の管理を簡素化するために重要です。
- 状態を取得するための直接的なインターフェースは、実装の詳細を公開し、オブジェクトのカプセル化を破ることになります。
Javaにおけるメメントパターンの実際の応用
メメントパターンは、java.util.Dateやjava.util.Calendarクラスなど、以前の状態に戻ることができるさまざまなJavaアプリケーションで使用されています。また、テキストエディタやグラフィックエディタのアンドゥメカニズムでも一般的です。
メメントパターンの利点とトレードオフ
利点
- カプセル化の境界を維持します。
- バージョン履歴やアンドゥ機能を直接管理する必要性をなくすことで、オリジネータを簡素化します。
トレードオフ
- 多数の状態が保存されている場合、メモリの観点からコストがかかる可能性があります。
- メモリリークを避けるために、メメントのライフサイクルを管理するために注意が必要です。