• 検索結果がありません。

DesignPattern(No6) 2003/07/28 Visitor 特徴データ構造と処理を分離し, データ構造内を巡り歩く 訪問者 クラスを作成し, そのクラスに処理を任せる このパターンでは, データ構造と処理が分離しているため, 処理の拡張は容易に行なえる ( しかし, データ構造の拡張

N/A
N/A
Protected

Academic year: 2021

シェア "DesignPattern(No6) 2003/07/28 Visitor 特徴データ構造と処理を分離し, データ構造内を巡り歩く 訪問者 クラスを作成し, そのクラスに処理を任せる このパターンでは, データ構造と処理が分離しているため, 処理の拡張は容易に行なえる ( しかし, データ構造の拡張"

Copied!
18
0
0

読み込み中.... (全文を見る)

全文

(1)

Visitor

特徴

データ構造と処理を分離し,データ構造内を巡り歩く「訪問者」クラスを作成し,そのクラスに処理を任せ る。 このパターンでは,データ構造と処理が分離しているため,処理の拡張は容易に行なえる(しかし,デ ータ構造の拡張は困難).

クラス図

Visitor visit(ConcreteElementA) visit(ConcreteElementB) Element accept( ) ConcreteElementA accept( ) ConcreteElementB accept( ) ConcreteVisitor visit(ConcreteElementA) visit(ConcreteElementB) ObjectStructure データ構造 「訪問者」 操作 各クラスの説明 Visitor 「訪問者(の API)」 データ構造の具体的要素(ConcreteElementA,B)を訪問するためのメソッドを宣言す るインタフェース(API) ConcreteVisitor 「具体的な訪問者」

Visitor クラス(これは API)を実装するクラス.データ構造の訪問先を引数に持つ visit メソッドを実装(多重定義)し,引数に内容により訪問する先を設定する.

Element

「受入先(者)(の API)」

Visitor の訪問先の役割をするクラス.訪問者(Visitor)を受け入れる accept メソッドを 宣言する.具体的な受入先のインターフェースである.

ConcreteElement

「具体的な受入先(者)」

Element クラスのインターフェース(API)を実装するクラス.

ObjectStructure Element クラス(の実装クラス(Concrete Element クラス))の集合を管理するクラス

プログラム例

階層構造をするディレクトリ内を訪問者が訪問し,そのディレクトリおよびファイルをフルパスで 表示するプログラムを考える.

Visitor を「訪問者」を表す抽象クラス、その実装クラスを ListVisitor クラスとする.この「訪問者」 のインスタンス(ListVisitor のインスタンス)は訪問先であるデータ構造(File と Directory から構成される 構造内)で訪問する.

< Visitor .java > 「訪問者」を表す抽象クラス(訪問するためのメソッドはデータ構造に依存する)

public abstract class Visitor {

public abstract void visit(File file); 引数がデータ構造の file, directory で区別 public abstract void visit(Directory directory);  多重定義

}

< ListVisitor .java > 「訪問者」を表す具体的なクラス(Visitor の実装クラス)

import java.util.Iterator;

public class ListVisitor extends Visitor {

private String currentdir = ""; // 現在注目しているディレクトリ名 public void visit(File file) { // ファイルを訪問したときに呼ばれる System.out.println(currentdir + "/" + file);

}

public void visit(Directory directory) { // ディレクトリを訪問したときに呼ばれる System.out.println(currentdir + "/" + directory);

String savedir = currentdir;

currentdir = currentdir + "/" + directory.getName(); Iterator it = directory.iterator();

(2)

while (it.hasNext()) {

Entry entry = (Entry)it.next(); entry.accept(this); } currentdir = savedir; } } < Acceptor .java > 訪問者を受け入れるための抽象クラス

public interface Acceptor {

public abstract void accept(Visitor v); // 訪問者を受け入れるメソッド (引数が 訪問者 Visitor)

}

< Entry .java > ディレクトリの階層構造を表現するため,クラスの再帰構造を作成する抽象クラス

(Composite パターンに類似)

import java.util.Iterator;

public abstract class Entry implements Acceptor {

public abstract String getName(); // 名前を得る (抽象メソッド) public abstract int getSize(); // サイズを得る (抽象メソッド)

public Entry add(Entry entry) throws FileTreatmentException { // エントリを追加する throw new FileTreatmentException( );

}

public Iterator iterator( ) throws FileTreatmentException { // Iterator の生成 throw new FileTreatmentException();

}

public String toString() { // 文字列表現 return getName() + " (" + getSize() + ")";

} }

< File .java > ファイルを表すクラス public class File extends Entry {

private String name; // ファイル名 private int size; // ファイルのサイズ public File(String name, int size) {

this.name = name; this.size = size; }

public String getName() { return name;

}

public int getSize() { return size; }

public void accept ( Visitor v ) { // 訪問者を受け入れるメソッド (引数が 訪問者 Visitor)

v.visit(this); // 戻り値は 自分 } } < Directory.java > ディレクトリを表すクラス import java.util.Iterator; import java.util.Vector;

public class Directory extends Entry {

private String name; // ディレクトリの名前

private Vector dir = new Vector( ); // ディレクトリエントリの集合 public Directory(String name) { // コンストラクタ

this.name = name; }

public String getName( ) { // 名前を得る return name;

[これが重要]

Visitor から Visitor インスタンスを渡され,そのインスタンスに自

(3)

}

public int getSize( ) { // サイズを得る int size = 0;

Iterator it = dir.iterator(); while (it.hasNext()) {

Entry entry = (Entry)it.next(); size += entry.getSize();

}

return size; }

public Entry add(Entry entry) { // エントリの追加 dir.add(entry);

return this; }

public Iterator iterator( ) { // Iterator の生成 return dir.iterator( );

}

public void accept(Visitor v) { // 訪問者を受け入れるメソッド (引数が 訪問者 Visitor) v.visit(this); // 戻り値は 自分

} }

< FileTreatmentException .java > 例外処理用のクラス

public class FileTreatmentException extends RuntimeException { public FileTreatmentException() { } public FileTreatmentException(String msg) { super(msg); } } < Main.java > Visitor クラスを利用するクラス

public class Main {

public static void main(String[] args) { try {

System.out.println("Making root entries..."); Directory rootdir = new Directory("root"); Directory bindir = new Directory("bin"); Directory usrdir = new Directory("usr"); rootdir.add(bindir); rootdir.add(usrdir); bindir.add(new File("vi", 10000)); bindir.add(new File("latex", 20000)); rootdir.accept(new ListVisitor( )); System.out.println("");

System.out.println("Making user entries..."); Directory yuki = new Directory("yuki"); Directory hanako = new Directory("hanako"); usrdir.add(yuki); usrdir.add(hanako); yuki.add(new File("diary.html", 100)); yuki.add(new File("Composite.java", 200)); hanako.add(new File("memo.tex", 300)); rootdir.accept(new ListVisitor( )); } catch (FileTreatmentException e) { e.printStackTrace(); } } } Directory インスタンスの作成 Directory インスタンス内に Directory インスタンスを入れる Directory インスタンス内に File インス タンスを作成して入れる 個人ユーザーの Directory インスタン スを作成 上で作成した個人ユーザーの Directory インスタンスを usr ディレクトリに入れる 個人ユーザーの Directory インスタンス に File インスタンスを作成して入れる root ディレクトリより,ファイルを訪問するため, root の accept( )に ListVisitor インスタンスを渡す

root ディレクトリより,ファイルを訪問するため, root の accept( )に ListVisitor インスタンスを渡す

Directory インスタンスを持つ

(4)

<実行結果>

D:¥Visitor¥Samplev2>java Main Making root entries...

/root (30000) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/usr (0)

Making user entries... /root (30600) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/usr (600) /root/usr/yuki (300) /root/usr/yuki/diary.html (100) /root/usr/yuki/Composite.java (200) /root/usr/hanako (300) /root/usr/hanako/memo.tex (300) Visitor visit(File) visit(Director) File name size accept( ) getName( ) getSize( ) Directory name dir accept( ) getName( ) getSize( ) add( ) iterator( ) ListVisitor currentdir visit (File) visit(Director) Acceptor accept( ) Element getName( ) getSize( ) add( ) iterator( ) Main Main クラス内で ListVisitor,File,Directory のインスタ ンスを保持する点に注意 訪問するメソッド (訪問者を) 受け入れるメソッド Main : ListVisitor accept ( )

:Directory :File :File

new visit ( ) accept ( ) visit ( ) ListVisitor がも う一度呼ばれる accept ( ) visit ( ) 1 つの Directory インスタンスへの訪問

(5)

Iterator

特徴

連続して存在するインスタンスに対して,順番に指し示して,全体をスキャンしていく処理を行なうパターン. (iteration=反復, iterator=反復子)

クラス図

ConcreteAggregate iterator( ) Aggregate iterator( ) Iterator hasNext() next( ) ConcreteIterator aggregate hasNext( ) next( ) 各クラスの説明 Iterator (反復子) インタフェース 要素(順番に並んだインスタンス)を順番に調べて行くためのクラスを設定 するインタフェース(API). hasNext( ) は「次の要素が存在するかを調べる」メソッド next( ) は「次の要素を得るため」のメソッド ConcreteIterator (具体的な反復子) Iterator インターフェース(のメソッド,API)を実際に実装するクラス Aggregate (集合体) インターフェース Iterator インスタンスを作成するためのインターフェース(API)を定めるクラス. (具体的には iterator メソッドの宣言) ConcreteAggregate (具体的な集合体) Aggregate インタフェース(のメソッド,API)を実際に実装するクラス (具体的には iterator メソッドの実装)

プログラム例

2 つのクラスに各5名の学生がいる.そこでクラス毎に学生の名前を登録し,その名前を登録順に表示する. なお,クラスと学生名はリストは以下である.

クラス: Tigers 学生:IMAOKA , AKAHOSHI, KANEMOTO, HIYAMA クラス: Giants 学生:NIOKA, MOTOKI, TAKAHASHI, KIYOHARA

< ClassRoom.java > // 「クラス」のクラス <このインスタンス内にデータ(Student インスタンス)を格納>

public class ClassRoom implements Aggregate {

private String name; // ClassRoom インスタンスの名前 private Student[] students; // 生徒(インスタンス)の配列 private int last = 0; // 配列の最終要素番号

public ClassRoom(String name, int maxsize) { // 引数は(名前,配列の最大要素数)

this.name= name;

this.students = new Student[maxsize]; }

public Student getStudentAt(int index) { // 配列の最終のデータを返す return students[index];

}

public void appendStudent(Student student) { // 配列に新しい生徒を格納する

this.students[last] = student; last++;

}

(6)

return last; }

public String getName( ) { // ClassRoom インスタンスの名前

return name; }

public Iterator iterator() { // 順次探索の操作を行うメソッド return new ClassRoomIterator(this);

} }

< Iterator.java > // 繰り返し処理を行うためのインターフェース public interface Iterator {

public abstract boolean hasNext( ); // 次の要素番号にデータが存在すかどうかを判断する抽象メソッ

public abstract Object next( ); // (並んだデータを)順次探索していく抽象メソッド

}

< ClassRoomIterator.java > // ClassRoom 内のデータ(Student)を順次(繰り返し)探索処理のためのクラス

public class ClassRoomIterator implements Iterator {

private ClassRoom classRoom; // ClassRoom インスタンスを保持 private int index; // その時点での要素番号 public ClassRoomIterator(ClassRoom classRoom) {

this.classRoom = classRoom; this.index = 0;

}

public boolean hasNext( ) { // 次の要素番号にデータが存在すかどうかを判断する抽象メソッド

if (index < classRoom.getLength( )) {

return true; // 次の要素も存在すれば true を返す } else {

return false; // 次の要素が存在しなければ false を返す }

}

public Object next( ) { // 要素番号 index でのデータ student を返す Student student = classRoom.getStudentAt(index);

index++; return student; }

}

< Student.java > // 要素データである生徒(Student)データを格納するクラス

public class Student {

private String name = ""; // 名前 public Student(String name) {

this.name = name; }

public String getName() { return name;

} }

< Aggregate .java > // 「集合体」を意味するインタフェース

// 要素データ(Student)を格納する集合体(ClassRoom)のインターフェース)

public interface Aggregate {

public abstract Iterator iterator(); }

< Main.java > // Iterator パターンを操作するためのクラス

public class Main {

public static void main(String[ ] args) { //---

ClassRoom tigers = new ClassRoom("Tigers", 4); // student の数を4人に設定 tigers.appendStudent(new Student("IMAOKA")); // 学生データの登録

(7)

tigers.appendStudent(new Student("AKAHOSHI")); tigers.appendStudent(new Student("KANEMOTO")); tigers.appendStudent(new Student("HIYAMA")); //---

ClassRoom giants = new ClassRoom("Giants", 4); // student の数を4人に設定 giants.appendStudent(new Student("NIOKA"));

giants.appendStudent(new Student("MOTOKI")); giants.appendStudent(new Student("TAKAHASHI")); giants.appendStudent(new Student("KIYOHARA")); //---

Iterator it; // Iterator クラスの変数

it = tigers.iterator(); //ClassRoom の iterator メソッドを呼ぶ

System.out.println("*** ClassRoom: "+tigers.getName()); out(it);

it = giants.iterator( );

System.out.println("*** ClassRoom: "+giants.getName()); out(it);

}

static void out(Iterator it){ while (it.hasNext()) {

Student student = (Student)it.next();

System.out.println("" + student.getName()); } } } <実行結果> E:¥Iterator¥Samplev2>java Main *** ClassRoom: Tigers IMAOKA AKAHOSHI KANEMOTO HIYAMA *** ClassRoom: Giants NIOKA MOTOKI TAKAHASHI KIYOHARA

(8)

ClassRoom name students last iterator( ) getName( ) getLength() appendStudent( ) getStudentAt( ) Aggregate iterator( ) Iterator hasNext() next( ) ClassRoomIterator classRoom index hasNext( ) next( ) Student name getName ( ) Main Create

Mediator

特徴

「Mediator=調停者,相談役」を利用して,システム上に存在する複数のインスタンス間の情報交換を管 理するパターン.複数の「メンバー役(=Colleaggue)」が互いの状態に関係してそれぞれ異なる情報や操作 を持つが,「相談役」が各メンバーを管理して情報を操作することによってメンバー間の情報交換を行なう. 複数のインスタンス間の情報交換(相互作用)をカプセル化するパターンであり,インスタンス間が互いに 明示的に参照し合わない構造を持つ.「メンバー」から見た場合は情報を渡す相手は「相談役」のみ. このパターンにより,インスタンス間の情報交換の変更を容易にする.

クラス図

Colleague mediator setMediator( ) controlColleague( ) ConcreteColleague1 controlColleague( ) ConcreteColleague2 controlColleague( ) Mediator createCollegues( ) colleagueChanged( ) Client ConcreteMediator ConcreteCollegue1 ConcreteCollegue2 createCollegues( ) colleagueChanged( ) 各クラスの説明 Mediator (「相談役」のインターフェース) 「相談役」の役割をするインターフェース(API) 「メンバー役」のインスタンスを保持すると共に,「メンバー 役」のインスタンスからの“相談”を受け取る処理を行なう. ク ラ ス 図 内 createCollegues( ) で 具 体 的 な メ ン バ ー (concreteColleague の イ ン ス タ ン ス ) を 生 成 し , colleagueChanged( )で各メンバーからの“相談”受ける. ConcreteMediator (具体的な「相談役」) Mediator インターフェースの実装クラス Mediator 内のメソッドを実装するクラス Colleague 「相談役」に“相談”を通知する「メンバー役」のインターフェース

(9)

(「メンバー,同僚役」イ ンターフェース) ConcreateColleague (具体的な「メンバー,同僚役」) Colleague インターフェースの実装クラス Client (依頼者) Mediator パターンを利用するクラス

プログラム例

自分の状態を整数で保持する「メンバー」が3種類存在する.これらのメンバーは状態の変更が外部より(渡さ れて)設定される.(その状態は Madiator が管理し,Mediator から各メンバーに渡される) 自分の状態が①7 の倍数(concreteCollege1),②偶数(同 2),③5 の倍数(同 3),のとき自分の状態が“臨界状 態”に変化したとして,Mediator に通知する. Mediator は通知を受け,①の場合はその状態を他の2つの「メンバー」に通知する.②の場合はその時点で の状態を 2 倍にし,③のメンバーに通知する.③の場合はその時点での状態を 3 倍にし,①のメンバーに通知 する. これにより,Mediator を通して,(1)相談役から各メンバーに通知し,条件や状態によって(2)各メンバーから相 談役に通知する構造ができる. < Mediator java> 相談役のインターフェース

public interface Mediator {

public abstract void createColleagues( ); // 「メンバー」を作成するメソッド

public abstract void colleagueChanged(Colleague colleague); // メンバーの状態変化を通知するメソッド

//----テスト用

public void setTestStatus(String cc, int status); }

< concreteMediator .java> Mediator の実装クラス ( メンバー(Colleague)のインスタンスを持つ)

public class concreteMediator implements Mediator { private concreteColleague1 cc1;

private concreteColleague2 cc2; 各メンバーのインスタンス private concreteColleague3 cc3;

private int status; // 状態(各メンバーに通知する) // コンストラクタ (Colleague インスタンスを作成する)

public concreteMediator( ) {

createColleagues( ); // Colleague のインスタンスを生成するメソッド }

// Colleague のインスタンスを生成するメソッド

public void createColleagues( ) {

// インスタンスの生成 cc1= new concreteColleague1( ); cc2= new concreteColleague2( ); cc3= new concreteColleague3( ); // Mediator のセット cc1.setMediator(this); cc2.setMediator(this); cc3.setMediator(this); } // concreteColleague から(変更したとの)通知があった場合, // どの concreteColleague であるかを判断して,該当する処理を行なう

public synchronized void colleagueChanged(Colleague c) { (C)

if(c == cc1){ //concreteColleague1 に変更があった場合は他の 2 つに状態 status を変更するよう指示

cc2.setColleagueEnabled(status);

各 Colleague のインスタンスに自分(concrete Mediator のイン スタンス)を渡し,保持してもらう

―→ 各 Colleague と Mediator 間に相互関連を持たせる コンストラクタの呼び出し

Colleague のメソッドを利用している点に注意 このメソッドが問題

(10)

cc3.setColleagueEnabled(status);

} else if(c == cc2){ // concreteColleague2 に変更があった場合は‘status を 2 倍’にし,

// concreteColleague3 にその status を変更するよう指示 status*=2;

cc3.setColleagueEnabled(status);

} else if (c == cc3) { // concreteColleague3 に変更があった場合は‘status を 3 倍’にし,

// concreteColleague1 にその status を変更するよう指示 status*=3; (G) cc1.setColleagueEnabled(status); } else{ // 該当する concreteColleague がない場合(強制終了) System.out.println("colleagueChanged:unknown colleague = " + c); System.exit(1); } System.out.println("¥n****変更したクラスは"+c); System.out.println("---"); cc1.showState( ); System.out.println("---"); (H) cc2.showState( ); System.out.println("---"); cc3.showState( ); } //----テスト用 (引数に文字列(concreteColleague の名)と状態を設定する // (これは単に colleagueChanged メソッドを動かすプログラム)) public void setTestStatus(String cc, int status){ ← (B)

this.status=status;

if(cc.compareTo("cc1")==0) colleagueChanged(cc1); else if(cc.compareTo("cc2")==0) colleagueChanged(cc2); else colleagueChanged(cc3); }

}

< Colleague.java > 「メンバー」用クラスのインターフェース

public interface Colleague {

public abstract void setMediator(Mediator mediator); // Mediator インスタンスをフィールドに設定する

public abstract void setColleagueEnabled(int status); // Mediator から状態を渡す(指示される)メソッド

}

< concreteColleague1 .java > Colleague インターフェースの実装クラス ①

public class concreteColleague1 implements Colleague {

private Mediator mediator; // Mediator インスタンス private final String name="concreteColleague1"; // 自分の名前

private int status=0; // 自分の状態(整数で設定)

private int count=0; // カウント(Mediator から指示された回数)

public void setMediator(Mediator mediator) { // Mediator インスタンスをフィールドに設定する

this.mediator = mediator; }

public void setColleagueEnabled(int status) { // Mediator から状態が指示される this.status = status;

count++;

if(status%7==0){

System.out.println("**** 変更したことを Mediator に送ります::"+name);

mediator.colleagueChanged(this); // 状態が変化したら Mediator に通知(引数は自分) }

(11)

public void showState(){ System.out.println("Name = "+name); System.out.println("状態 = "+status); System.out.println("Mediator からの指示回数=" + count); } }

< concreteColleague2 .java > Colleague インターフェースの実装クラス ② (concreteColleague1 と※が異なる)

public class concreteColleague2 implements Colleague {

private Mediator mediator; // Mediator インスタンス private final String name="concreteColleague2"; // 自分の名前

private int status=0; // 自分の状態(整数で設定)

private int count=0; // カウント(Mediator から指示された回数) public void setMediator(Mediator mediator) { // Mediator を保持

this.mediator = mediator; }

public void setColleagueEnabled(int status) { // Mediator から状態が指示される (D) this.status = status;

count++;

if(status%2==0){ // status が偶数ならば状態が変化したとする ※ System.out.println("**** 変更したことを Mediator に送ります::"+name);

mediator.colleagueChanged(this); // 状態が変化したら Mediator に通知(引数は自分) }

}

public void showState( ){ // 自分の状態を画面表示するメソッド System.out.println("Name = "+name);

System.out.println("状態 = "+status); System.out.println("Mediator からの指示回数=" + count); }

}

< concreteColleague3 .java > Colleague インターフェースの実装クラス ③ (concreteColleague1 と※が異なる)

public class concreteColleague3 implements Colleague {

private Mediator mediator; // Mediator インスタンス private final String name="concreteColleague3"; // 自分の名前

private int status=0; // 自分の状態(整数で設定)

private int count=0; // カウント(Mediator から指示された回数) public void setMediator(Mediator mediator) { // Mediator を保持

this.mediator = mediator; }

public void setColleagueEnabled(int status) { // Mediator から状態が指示される (D) this.status = status;

count++;

if(status%5==0){ //status が 5 の倍数ならば状態が変化したとする ※ (E) System.out.println("**** 変更したことを Mediator に送ります::"+name);

mediator.colleagueChanged(this); //状態が変化したら Mediator に通知(引数は自分) (F)

} }

public void showState(){

System.out.println("Name = "+name);

(12)

System.out.println("Mediator からの指示回数=" + count); }

}

< Main .java> パターンを操作するクラス

public class Main {

static public void main(String args[]) {

Mediator md=new concreteMediator( );

md.setTestStatus("cc1", 5); // 実行を開始するメソッドの呼び出し (A) } } <実行結果> E:¥>java Main **** 変更したことを Mediator に送ります::concreteColleague3 ****変更したクラスはconcreteColleague3@e63e3d ( I ) --- Name = concreteColleague1 状態 = 15 Mediator からの指示回数=1 --- Name = concreteColleague2 状態 = 5 Mediator からの指示回数= 1 --- Name = concreteColleague3 状態 = 5 Mediator からの指示回数=1 ****変更したクラスは concreteColleague1@4901 --- Name = concreteColleague1 状態 = 15 Mediator からの指示回数=1 --- Name = concreteColleague2 状態 = 5 Mediator からの指示回数= 1 --- Name = concreteColleague3 状態 = 5 Mediator からの指示回数=1 Colleague setMediator(mediator) setColleagueEnabled(status) Mediator createCollegues( ) colleagueChanged( Colleague) setTestStatus Main ConcreteMediator ConcreteCollegue1 ConcreteCollegue2 ConcreteCollegue3 status createCollegues( ) colleagueChanged( ) setTestStatus( ) ConcreteColleague2 mediator name status count setMediator(mediator) setColleagueEnabled(status) showState ( ) ConcreteColleague3 mediator name status count setMediator(mediator) setColleagueEnabled(status) showState ( ) ConcreteColleague1 mediator name status count setMediator(mediator) setColleagueEnabled(status) showState ( ) Main メソッドより状態 5, concreteColleague1 より通 知された(A)として Mediator 内の colleagueChanged

メソッドを実行する.(B) そのメソッド内で状態は 5 となり,concreteColleague ②,③に状態 5 が通知される(C).そして,通知された 各インスタンス内で状態 5 が設定され(D),③ではさ らに(5 の倍数なので)状態が変化したと Mediator に 通知する(E). この表示はconcreteColleague3 内での表示

そ し て , (concreteColleague ③ 内 よ り ) 再 び Mediator の colleague

Changed メソッドを実行する.引数は③のインスタンス.(F) colleagueChanged メ ソ ッ ド 内 で 状 態 は 15(=3*5) と な り , ① に setColleagueEnabled によって状態 15 が通知され(G),そのメソッドが終 了する. これで,2回目に呼び出された colleagueChanged メソッドが終了し,最後 に①∼③内の状態が表示される.(H) (このため, 実行結果の「***変更したクラスは」が③となっている.( I )) ※ ①,②,③はそれぞれconcreteColleague1, 2, 3 インスタンスを指す

(13)

: Client : concreteMediator setTestStatus ( ) :concreteCollegue1 :concreteCollegue2 colleagueChanged ( ) :concreteCollegue3 setColleagueEnabled ( ) setColleagueEnabled ( ) setColleagueEnabled ( )

Memento

特徴

インスタンスの状態を保存するパターン.このパターンにより,過去に保存した状態を元に戻すことがで きる.(memento=「記念品」)

クラス図

Memento state getState( ) setState( ) Originator state createMemento( ) setMemento(Memento m) CareTaker Requests Creates 各クラスの説明 Originator (作成者) 保存の対象となるインスタンスを生成するクラス.また,以下の操作を行なう ①自分の現在の状態を保存したい場合にMemento インスタンスを(createMemento メ ソッドにより)作成する.(インスタンスを作るように指示した CareTaker インスタ ンスにその Memento インスタンスを渡す) ②過去の Memento インスタンスを渡されると,その Memento インスタンスを作成し た時点の状態に戻る処理(setMemento メソッドにより)を行なう. Memento (記念品) Originator インスタンスの内部情報(状態)を保持するクラス. 保持する情報は公開しない.(インスタンスのカプセル化) CareTaker (世話をする者) 現在の Originator インスタンスの状態を保存する場合に Originator インスタンスに情報を伝 えるクラス.(Originator は Memento インスタンスを作成し,CareTaker インスタンスへ渡す.) そして,作成された Memento インスタンスを保存する.

プログラム例

(14)

name).さらに,データ構造には文字列を格納した時点での発生順番を“状態(Originator の status)”として格納 する.任意の文字列の生成を20回行い,5回毎にバックアップをとる.(Memento)

20回の文字列の生成,格納後,バックアップした最新の情報の戻す. なお,Originator と Memento クラスはパッケージ memento に格納する.

Memento int status Vector name getStaus ( ) addName ( ) Originator int status Vector name setStatus ( ) setName ( ) out( ) createMemento( ) restoreMemento( ) Main main( ) generateString( ) Requests Creates <Originator.java> データ構造の元(コピー(Momento)を作成する操作を持つ) package memento; import java.util.Vector; public class Originator {

private int status; // 順番号(何回処理したか)

private Vector name = new Vector(); // 名前を格納するリスト

public Originator( ) { // コンストラクタ

this.status = 0; // 状態(整数)の保存

this.name=new Vector(); // 文字列(名前)保存用リスト }

//---データの設定

public void setStatus(int status){ // 状態の設定 this.status=status;

}

public void setName(String s){ // 名前をリストに追加 name.add(s);

}

//--- // データの出力

public void out(){

System.out.println("---"); System.out.println(" Status:"+status); for(int i=0; i<name.size(); i++)

System.out.println(" "+name); System.out.println("---"); }

//---コピー(Memeto インスタンス)を作成するメソッド

public Memento createMemento() { // フィールド値の複製を作成する

Memento m = new Memento(status); // ①memento インスタンスの作成 for(int i=0; i<name.size() ;i++){

(15)

m.addName((String)name.get(i)); // ②文字列を追加 }

return m; }

public void restoreMemento(Memento memento) { //フィールド値を元(Originator インスタンス)に戻す

this.status = memento.status; // フィールド値のコピー

this.name = memento.name; // (とくに,vector インスタンスの参照をコピー) } //--- } <Memento.java> (フィールド値の)コピーとなるクラス package memento; import java.util.Vector; public class Memento {

int status; // 順番号(何回目のデータか) Vector name; // 名簿

Memento(int status) { // コンストラクタ(wide interface) this.status = status;

this.name = new Vector(); }

public int getStaus() { // 順番号を得る(narrow interface) return status;

}

void addName(String s) { // 名前を追加する(wide interface) name.add(s);

} }

<Main.java> Memento パターンを利用するクラス

import memento.*; public class Main {

public static void main(String[] args) { int NUM=10;

Originator org = new Originator(); // Originator クラスの生成

Memento memento = org.createMemento(); // コピーのインスタンスを保持(最初の状態を保存)

String name;

for (int i = 0; i < NUM; i++) {

System.out.println("==== " + i); // 回数表示 //--- 任意の文字列の作成 name=generateString(); // 下に記述するメソッドを利用 //--- データ構造にデータを格納 org.setStatus(i); org.setName(name); //--- // 3 件データが格納された時点でバックアップをとる if(i%3==2){ System.out.println("<<バックアップをとる>>"); memento = org.createMemento( ); // コピーを取るメソッドを呼び出す } //---

(16)

−16− // 時間待ち try { Thread.sleep(1000); } catch (InterruptedException e) { } //--- org.out (); //画面出力 } System.out.println("<<バックアップの状態に戻す>>"); org.restoreMemento(memento); // バックアップの状態に戻すメソッドの呼び出し org.out(); } //-- 任意の5文字の文字列を作成するメソッド

static String generateString(){ int NUM=4;

char[] str= new char[NUM]; for(int i=0; i<NUM-1; i++)

str[i]=(char)((int)(Math.random()*26)+'A'); str[NUM-1]='¥0';

return (new String(str)); // char 配列の文字列を String 型へ変換 } } <実行結果> ==== 0 --- Status:0 [DQJ ] --- ==== 1 --- Status:1 [DQJ , HBI ] [DQJ , HBI ] --- ==== 2 <<バックアップをとる>> --- Status:2 [DQJ , HBI , AVZ ] [DQJ , HBI , AVZ ] [DQJ , HBI , AVZ ] --- ==== 3 --- Status:3

[DQJ , HBI , AVZ , BTE ] [DQJ , HBI , AVZ , BTE ] [DQJ , HBI , AVZ , BTE ] [DQJ , HBI , AVZ , BTE ] ---

==== 4

--- Status:4

[DQJ , HBI , AVZ , BTE , QIO ] [DQJ , HBI , AVZ , BTE , QIO ] [DQJ , HBI , AVZ , BTE , QIO ] [DQJ , HBI , AVZ , BTE , QIO ]

この時点で Original と Memento のインスタ ンスには同じ Status:2 のデータが入って いる この時点で Original と Memento のインスタ この時点では Original は Status:3 のデー タ,Memento のインスタンスには Status:2 のデータが入っている この時点では Original は Status:4 のデー タ,Memento のインスタンスには Status:2 のデータが入っている この時点では Original は Status:1 のデー タ,Memento のインスタンスには Status:0 のデータが入っている

(17)

[DQJ , HBI , AVZ , BTE , QIO ] --- ==== 5 <<バックアップをとる>> --- Status:5

[DQJ , HBI , AVZ , BTE , QIO , BWG ] [DQJ , HBI , AVZ , BTE , QIO , BWG ] [DQJ , HBI , AVZ , BTE , QIO , BWG ] [DQJ , HBI , AVZ , BTE , QIO , BWG ] [DQJ , HBI , AVZ , BTE , QIO , BWG ] [DQJ , HBI , AVZ , BTE , QIO , BWG ] ---

==== 6

--- Status:6

[DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF ] ---

==== 7

--- Status:7

[DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ ] ---

==== 8

<<バックアップをとる>> --- Status:8

[DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] ---

==== 9

--- Status:9

[DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE , NRK ] ---

(18)

<<バックアップの状態に戻す>> ---

Status:8

[DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] [DQJ , HBI , AVZ , BTE , QIO , BWG , KTF , AEQ , ECE ] ---

(注意)

①本プログラムでは Originator , Memento クラスはパッケージ memento 内に存在している.

そして Memento クラスでは status, name のフィールド値は private でないが,class が pubulic ではないた め,Memento クラスは同一のパッケージ内からでしかアクセスできない.(つまり,Originator クラスからでした アクセスできない.)

②Memento インスタンス内の文字列を Originator に戻す場合は Memento インスタンス内の Vector の参照を

戻している.(つまり,必ず Memento インスタンスと Originator インスタンスが共存し,両インスタンスが name

を参照する.) Memento int status Vector name getStaus ( ) addName ( ) Originator int status Vector name setStatus ( ) setName ( ) out( ) createMemento( ) restoreMemento( ) Creates Memento int status Vector name getStaus ( ) addName ( ) Memento int status Vector name getStaus ( ) addName ( ) Memento int status Vector name getStaus ( ) addName ( ) 1 回目の コピー 2 回目の コピー 3 回目の コピー 4 回目の コピー コピー コピーでは name 内の データは残る 不要になった時点で 削除(ガーベージコレ クション) この時点で Original と Memento のインスタ ンスには同じ Status:8 のデータが入って いる 左の結果は(Original インスタンスを表示す ると) Status:8 である.

参照

関連したドキュメント

 処分の違法を主張したとしても、処分の効力あるいは法効果を争うことに

実際, クラス C の多様体については, ここでは 詳細には述べないが, 代数 reduction をはじめ類似のいくつかの方法を 組み合わせてその構造を組織的に研究することができる

このエアコンは冷房運転時のドレン(除湿)水を内部で蒸発さ

あれば、その逸脱に対しては N400 が惹起され、 ELAN や P600 は惹起しないと 考えられる。もし、シカの認可処理に統語的処理と意味的処理の両方が関わっ

これら諸々の構造的制約というフィルターを通して析出された行為を分析対象とする点で︑構

り分けることを通して,訴訟事件を計画的に処理し,訴訟の迅速化および低

(注)