倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

「GoF デザインパターン」アノテーション (18) : Memento パターン

今回は Memento パターン一覧)。

Memento ・・・記念の品,形見; 思い出の種

Memento パターンの登場人物

  • @Caretaker → 型
    • mementoType : Class<?>
  • @Originator → 型
    • mementoType : Class<?>
    • @CreateMemento → メソッド
    • @RestoreMemento → メソッド
  • @Memento → 型
    • @GetProtectedInfo → メソッド
    • @GetPublicInfo → メソッド

アノテーション定義


上記の定義の具体的な Java コード。

package org.waman.tools.design.gof.behavioral;

import java.lang.annotation.*;

public final class MementoPattern {
    
    private MementoPattern(){}

    @Target(ElementType.TYPE)
    public static @interface Memento{

        @Inherited @Target(ElementType.METHOD)
        public static @interface GetProtectedInfo{}

        @Inherited @Target(ElementType.METHOD)
        public static @interface GetPublicInfo{}
    }

    @Target(ElementType.TYPE)
    public static @interface Originator{
        
        Class<?> mementoType() default Void.class;

        @Inherited @Target(ElementType.METHOD)
        public static @interface CreateMemento{}

        @Inherited @Target(ElementType.METHOD)
        public static @interface RestoreMemento{}
    }

    @Target(ElementType.TYPE)
    public static @interface Caretaker{
        Class<?> mementoType() default Void.class;
    }
}

サンプルコード in 『Java 言語で学ぶデザインパターン入門』


Memento.java

@Memento 役のクラス。

import java.util.*;

import org.waman.tools.design.gof.behavioral.MementoPattern;
import org.waman.tools.design.gof.behavioral.MementoPattern.Memento.GetProtectedInfo;
import org.waman.tools.design.gof.behavioral.MementoPattern.Memento.GetPublicInfo;

@MementoPattern.Memento
public class Memento {
    
    int money;
    final List<String> fruits = new ArrayList<String>();
    
    Memento(int money) {
        this.money = money;
    }
    
    @GetPublicInfo public int getMoney() {
        return money;
    }
    
    @GetProtectedInfo void addFruit(String fruit) {
        fruits.add(fruit);
    }
    
    @GetProtectedInfo List<String> getFruits() {
         return new ArrayList<String>(fruits);
    }
}

Gamer.java

@Originator 役のクラス。

import java.util.*;

import org.waman.tools.design.gof.behavioral.MementoPattern;
import org.waman.tools.design.gof.behavioral.MementoPattern.Originator.CreateMemento;
import org.waman.tools.design.gof.behavioral.MementoPattern.Originator.RestoreMemento;

@MementoPattern.Originator(mementoType = Memento.class)
public class Gamer {

    private int money;
    private List<String> fruits = new ArrayList<String>();
    ...

    @CreateMemento public Memento createMemento() {
        Memento m = new Memento(money);
        
        for(String fruit: fruits) {
            if (fruit.toString().startsWith("おいしい"))
                m.addFruit(fruit);
        }

        return m;
    }
    
    @RestoreMemento public void restoreMemento(Memento memento) {
        this.money = memento.money;
        this.fruits = memento.getFruits();
    }
    ...
}

Main.java

@Caretaker 役のクラス。

import org.waman.tools.design.gof.behavioral.MementoPattern;

import sample.gof.behavioral.memento.game.Gamer;
import sample.gof.behavioral.memento.game.Memento;

@MementoPattern.Caretaker(mementoType = Memento.class)
public class Main {
    
    public static void main(String[] args) {
        Gamer gamer = new Gamer(100);
        Memento memento = gamer.createMemento();
        
        for (int i = 0; i < 100; i++) {
            ...
            if (gamer.getMoney() > memento.getMoney()) {
                System.out.println("    (だいぶ増えたので、現状の状態を保存しておこう)");
                memento = gamer.createMemento();
                
            } else if (gamer.getMoney() < memento.getMoney() / 2) {
                System.out.println("    (だいぶ減ったので、以前の状態に復帰しよう)");
                gamer.restoreMemento(memento);
            }
            ...
        }
    }
}

増補改訂版Java言語で学ぶデザインパターン入門 オブジェクト指向における再利用のためのデザインパターン Code Complete第2版〈上〉―完全なプログラミングを目指して Code Complete第2版〈下〉―完全なプログラミングを目指して