Skeleton of GOF's Design Pattern


MEMENTの骸骨

MEMENT

状態を生成するクラスと状態の履歴の管理をするクラスを分離するパターンです。状態を生成するクラスを Originator、状態を保管するクラスを Memento、状態を管理するクラスを CareTaker と呼びます。

このパターンの特徴は、一時的に記録した状態をまた取り込んでオブジェクトの状態をもとに戻せるという点です。MEMENTO は、各クラス間のインターフェースのアクセス制御を注意深く設計する必要がある点に注意してください。。


■ 『MEMENTOの骸骨』の構造


■ 『MEMENTOの骸骨』の特徴的な協調関係


■ 『MEMENTOの骸骨』 プログラム・コード

□ Java2版
// Copyright(C) 2000-2003 Yoshinori Oota All rights reserved.

import java.util.*;

public class MementoSample {
    static public void main(String[] args) {
        String crlf = System.getProperties().getProperty("line.separator");

        Originator originator = new Originator();
        CareTaker caretaker = new CareTaker(originator);

        originator.Write("古池や蛙飛び込む池の音。" + crlf);
        caretaker.Save(); // 最初の状態を記録(1世代目)

        originator.Write("雀の子そこのけそこのけ御馬が通る。つづいて、");
        originator.Write("夏草や兵どもが夢のあと。" + crlf);
        caretaker.Save(); // 2世代目の状態を記録

        originator.Write("馬ぼくぼく我を絵にみん夏野哉。さらに、");
        originator.Write("馬かたはしらじしぐれの大井川。" + crlf);
        caretaker.Save(); // 3世代目の状態を記録
        originator.print();

        // 2世代の状態にセットしよう!
        caretaker.PutBack(1);
        originator.print();

        // 最初の状態にセットしよう!
        caretaker.PutBack(0);
        originator.print();

        // 3世代目の状態に戻してみよう!
        caretaker.PutBack(2);
        originator.print(); 
    } 
}

class CareTaker { 
    private Originator _originator = null;
    private LinkedList _mementos = new LinkedList();
    public CareTaker(Originator originator) { 
        _originator = originator;
    }
    public void Save() { 
        Memento memento = _originator.CreateMement();
        _mementos.add(memento);
    }
    public void PutBack(int index) {
        if (index >= _mementos.size()) return;
        Memento memento = (Memento)_mementos.get(index);
        _originator.SetMemento(memento); 
    }
}

class Originator {
    private String _words = "";
    Memento CreateMement() { 
        return new Memento(_words);
    }
    void SetMemento(Memento memento) { 
        _words = memento.GetSnapshot();
    }
    public void Write(String words) { 
        _words += words;
    }
    public void print() { 
        System.out.println("*****************************");
        System.out.println(_words);
    } 
} 

class Memento { 
   private String _snapshot = null;
   Memento(String words) {
       _snapshot = new String(words);
   }
   String GetSnapshot() { 
       return _snapshot; 
   }
}

○ C++版
// Copyright(C) 2003 Yoshinori Oota All rights reserved.

#include <vector>
#include <iostream>
using namespace std;

class Originator;
class CareTaker;
class Memento;

class CareTaker {
public:
    CareTaker(Originator* originator);
    ~CareTaker();
    void Save();
    void PutBack(int index);
private:
    Originator* originator_;
    vector<Memento*> mementos_;
};

class Originator {
public:
    Originator();
    ~Originator();
    void print() const;
    void Write(const string& words);
protected:
    friend class CareTaker;
    Memento* CreateMemento();
    void SetMemento(Memento* m);
private:
    string words_;
};

class Memento {
public:
    ~Memento();
protected:
    friend class Originator;
    Memento(const string& words);
    const string& GetSnapshot();
private:
    string snapshot_;
};


CareTaker::CareTaker(Originator* org) : originator_(org) { }
CareTaker::~CareTaker() {
    vector<Memento*>::iterator it = mementos_.begin();
    while (it != mementos_.end()) {
        delete (*it);
        ++it;
    }
}
void CareTaker::Save() {
    Memento* memento = originator_->CreateMemento();
    mementos_.push_back(memento);
}
void CareTaker::PutBack(int index) {
    if (index >= mementos_.size()) return;
    Memento* memento = mementos_[index];
    originator_->SetMemento(memento);
}

Originator::Originator() : words_("") { }
Originator::~Originator() { }
void Originator::Write(const string& words) {
    words_ += words;
}
Memento* Originator::CreateMemento() {
    return new Memento(words_);
}
void Originator::SetMemento(Memento* memento) {
    words_ = memento->GetSnapshot();
}
void Originator::print() const {
   cout << "******************" << endl;
   cout << words_ << endl;
}

Memento::Memento(const string& words) : snapshot_(words) { }
Memento::~Memento() { }
const string& Memento::GetSnapshot() {
    return snapshot_;
} 


int main() {
    Originator* originator = new Originator();
    CareTaker* caretaker = new CareTaker(originator);

    originator->Write("古池や蛙飛び込む池の音。\r\n");
    caretaker->Save(); // 最初の状態を記録(1世代目)

    originator->Write("雀の子そこのけそこのけ御馬が通る。つづいて、");
    originator->Write("夏草や兵どもが夢のあと。\r\n");
    caretaker->Save(); // 2世代目の状態を記録

    originator->Write("馬ぼくぼく我を絵にみん夏野哉。さらに、");
    originator->Write("馬かたはしらじしぐれの大井川。\r\n");
    caretaker->Save(); // 3世代目の状態を記録
    originator->print();

    // 2世代の状態にセットしよう!
    caretaker->PutBack(1);
    originator->print();

    // 最初の状態にセットしよう!
    caretaker->PutBack(0);
    originator->print();

    // 3世代目の状態に戻してみよう!
    caretaker->PutBack(2);
    originator->print(); 

    delete caretaker;
    delete originator;
}

○ C版
/* Copyright(C) 2009 Yoshinori Oota All rights reserved. */
#include <stdio.h>
#include <stdlib.h>

struct Memento;

/* Originator Interface */
struct Originator {
    int saved_;
    char* words_;
    void (*Print)(struct Originator* pthis);
    void (*Write)(struct Originator* pthis ,const char* words);
    struct Memento* (*CreateMemento)(struct Originator* pthis);
    void (*SetMemento)(struct Originator* pthis ,struct Memento* m);
};
struct Originator* New_Originator();
void Delete_Originator(struct Originator* org);
void Originator_Print(struct Originator* pthis);
void Originator_Write(struct Originator* pthis ,const char* words);
struct Memento* Originator_CreateMemento(struct Originator* pthis);
void Originator_SetMemento(struct Originator* pthis ,struct Memento* memento);

/* Memento Interface */
struct Memento {
    char* snapshot_;
    char* (*GetSnapshot)(struct Memento* pthis);
};
struct Memento* New_Memento(char* words);
void Delete_Memento(struct Memento* memento);
char* Memento_GetSnapshot(struct Memento* pthis);

/* Originator Class Implementation */
struct Originator* New_Originator() {
    struct Originator* orginator = (struct Originator*)malloc(sizeof(struct Originator));
    orginator->saved_ = 0;
    orginator->words_ = NULL;
    orginator->Print  = &Originator_Print;
    orginator->Write  = &Originator_Write;
    orginator->SetMemento  = &Originator_SetMemento;
    orginator->CreateMemento = &Originator_CreateMemento;
    return originator;
}

void Delete_Originator(struct Originator* orginator) {
    if (originator == NULL) {
        return;
    }
    free(orginator->words_);
    orginator->words_ = NULL;
    free(orginator);
    orginator = NULL;
    return;
}

void Originator_Write(struct Originator* pthis ,const char *words) {
    char* buf = NULL;
    if (pthis->words_ != NULL && pthis->saved_ == 1) {  //すでに保存された文字なら上書き
        buf = (char*)malloc(strlen(words)+1);
        strcpy(buf ,words);
        pthis->saved_ = 0;                              //保存状態をリセット
        free(pthis->words_);
        pthis->words_ = buf;
    } else if (pthis->words_ != NULL && pthis->saved_ == 0) { //まだ保存されていない文字なら追記
        buf = (char*)malloc(strlen(pthis->words_)+strlen(words)+1);
        strcpy(buf, pthis->words_);
        strcat(buf, words);
        free(pthis->words_);
        pthis->words_ = buf;
    } else {
        buf = (char*)malloc(strlen(words)+1);
        strcpy(buf ,words);
        pthis->words_ = buf;
    }
    return;
}

struct Memento* Originator_CreateMemento(struct Originator* pthis) {
    struct Memento* memento = NULL;
    memento = New_Memento(pthis->words_);
    pthis->saved_ = 1;
    return memento;
}

void Originator_SetMemento(struct Originator* pthis ,struct Memento* memento) {
    char* snapshot = NULL;
    snapshot = memento->GetSnapshot(memento);
    if (pthis->words_ != NULL) {
        free(pthis->words_);
    }
    pthis->words_ = snapshot;
    return;
}

void Originator_Print(struct Originator* pthis) {
    printf("******************\n");
    printf("%s\n" ,pthis->words_);
    return;
}

/* Memento Class Interface */
struct Memento* New_Memento(char* words) {
    char* buf = NULL;
    struct Memento* memento = NULL;
    buf = (char*)malloc(strlen(words)+1);
    strcpy(buf ,words);
    memento = (struct Memento*)malloc(sizeof(struct Memento));
    memento->snapshot_ = buf;
    memento->GetSnapshot = &Memento_GetSnapshot;
    return memento;
}

void Delete_Memento(struct Memento* memento) {
    if (memento == NULL) {
       return;
    }
    free(memento->snapshot_);
    memento->snapshot_ = NULL;
    free(memento);
    memento = NULL;
    return;
}

char* Memento_GetSnapshot(struct Memento* pthis) {
    char* buf = NULL;
    buf = (char*)malloc(strlen(pthis->snapshot_)+1);
    strcpy(buf ,pthis->snapshot_);
    return buf;
}

/* CareTaker Implementation */
struct MementoList {
    struct Memento* memento_;
    struct MementoList* next_;
};
struct MementoList* gMementoTop  = NULL;
struct MementoList* gMementoLast = NULL;
int gMementoMaxNum = 0;

void CareTaker_Save(struct Originator* originator) {
    struct MementoList* list = NULL;

    list = (struct MementoList*)malloc(sizeof(struct MementoList));
    list->memento_ = originator->CreateMemento(originator);
    list->next_ = NULL;

    if (gMementoTop == NULL) {
        gMementoTop = list;
        gMementoLast = list;
    } else {
        gMementoLast->next_ = list;
        gMementoLast = list;
    }
    ++gMementoMaxNum;
   return;
}

void CareTaker_PutBack(struct Originator* originator ,int index) {
    int i = 0;
    struct MementoList* cur = gMementoTop;

    if (index >= gMementoMaxNum) return;
    while (i < index) {
       cur = cur->next_;
       ++i;
    }
    originator->SetMemento(originator ,cur->memento_);
    return;
}

void CareTaker_Clean() {
    struct MementoList* cur = NULL;
    struct MementoList* tmp = NULL;
    cur = gMementoTop;
    while (cur != NULL) {
        tmp = cur->next_;
        Delete_Memento(cur->memento_);
        free(cur);
        cur = tmp;
    }
    return;
}


int main() {
    struct Originator* originator = NULL;
    
    originator = New_Originator();

    originator->Write(originator ,"古池や蛙飛び込む池の音。\n");
    CareTaker_Save(originator); // 最初の状態を記録(1世代目)

    originator->Write(originator ,"雀の子そこのけそこのけ御馬が通る。つづいて、");
    originator->Write(originator ,"夏草や兵どもが夢のあと。\n");
    CareTaker_Save(originator); // 2世代目の状態を記録

    originator->Write(originator ,"馬ぼくぼく我を絵にみん夏野哉。さらに、");
    originator->Write(originator ,"馬かたはしらじしぐれの大井川。\n");
    CareTaker_Save(originator); // 3世代目の状態を記録
    originator->Print(originator);

    // 2世代の状態にセットしよう!
    CareTaker_PutBack(originator ,1);
    originator->Print(originator);

    // 最初の状態にセットしよう!
    CareTaker_PutBack(originator ,0);
    originator->Print(originator);

    // 3世代目の状態に戻してみよう!
    CareTaker_PutBack(originator ,2);
    originator->Print(originator); 
    
    Delete_Originator(originator);
    CareTaker_Clean();

    return 0;
} 


改訂履歴

2009.2.22 C言語版を追加
     
     

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2009 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。