📖
★ Java | Visitor Pattern
Java
Visitor Pattern概要
- アルゴリズムをオブジェクトの構造から分離して、新しい操作を柔軟に追加できるデザインパターン
- 分離による実用的な結果として、既存のオブジェクトに対する新たな操作を構造を変更せずに追加することができる。
Visitor Pattern特徴
Visitor Pattern特徴 | 内容 |
---|---|
データ構造と処理の分離 | データ構造を変更せずに新しい操作を追加できる。 |
拡張性 | 新しいVisitorを追加することで、既存の要素に新しい操作を適用できる。 |
要素の知識不要 | 要素はVisitorの存在を認識する必要がない。 |
図形描画処理でのVisitor Pattern適用例
- Visitorパターンを使用することで、図形の構造を変更せずに新しい操作(この場合は描画)を追加することができる。
- 以下のサンプルでは
Visitor
とAcceptor
という名前を使い、Visitorパターンの構造を明確にしている。
1. 図形のインターフェース(Acceptor)
-
ShapeAcceptor
インターフェース:
すべての図形が実装するインターフェースで、acceptメソッドを定義している。
このメソッドはVisitorを受け入れるために使用される。
interface ShapeAcceptor {
void accept(ShapeVisitor visitor);
}
2. 具体的な図形クラス(Acceptorの実装)
- 具体的な図形クラス:
Circle
とRectangle
はShapeAcceptor
インターフェースを実装し、それぞれのacceptメソッドでVisitorのvisitメソッドを呼び出す。
class Circle implements ShapeAcceptor {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
class Rectangle implements ShapeAcceptor {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
3. Visitorインターフェース
-
ShapeVisitor
インターフェース
ShapeVisitor
インターフェースは、各図形に対するvisitメソッドを定義している。
interface ShapeVisitor {
void visit(Circle circle);
void visit(Rectangle rectangle);
}
4. 具体的なVisitorクラス
-
DrawingVisitor
クラス:
DrawingVisitor
は、図形を描画するための具体的なVisitorで、各図形に対して異なる描画処理を実装している。
class DrawingVisitor implements ShapeVisitor {
@Override
public void visit(Circle circle) {
System.out.println("Drawing a Circle");
}
@Override
public void visit(Rectangle rectangle) {
System.out.println("Drawing a Rectangle");
}
}
5. 使用例
-
VisitorPatternExample
クラスで、図形を作成し、DrawingVisitor
を使って描画処理を行う例。
public class VisitorPatternExample {
public static void main(String[] args) {
ShapeAcceptor circle = new Circle();
ShapeAcceptor rectangle = new Rectangle();
ShapeVisitor drawingVisitor = new DrawingVisitor();
circle.accept(drawingVisitor); // "Drawing a Circle"
rectangle.accept(drawingVisitor); // "Drawing a Rectangle"
}
}
ダブルディスパッチの模倣
-
Circle
やRectangle
のaccept
メソッド内で、Visitor
のvisit
メソッドを呼び出している。 - この時、具体的な型(
Circle
やRectangle
)に基づいて、適切なvisit
メソッドが呼び出される。これがダブルディスパッチの模倣。
+---------------------------------------+
| ShapeAcceptor |
|---------------------------------------|
| + accept(visitor: ShapeVisitor): void |
+---------------------------------------+
^
| +---------------------------------------+
+-----| Circle |
| |---------------------------------------|
| | + accept(visitor: ShapeVisitor): void |
| +---------------------------------------+
|
| +---------------------------------------+
+-----| Rectangle |
|---------------------------------------|
| + accept(visitor: ShapeVisitor): void |
+---------------------------------------+
+-------------------------------------+
| ShapeVisitor |
|-------------------------------------|
| + visit(circle: Circle): void |
| + visit(rectangle: Rectangle): void |
+-------------------------------------+
^
|
+-------------------------------------+
| DrawingVisitor |
|-------------------------------------|
| + visit(circle: Circle): void |
| + visit(rectangle: Rectangle): void |
+-------------------------------------+
+------------------------------+
| VisitorPatternExample |
|------------------------------|
| + main(args: String[]): void |
+------------------------------+
+----------------+ +--------------------+
| Circle | | DrawingVisitor |
+----------------+ +--------------------+
| | | |
| accept() |---------->| visit(Circle) |
| | | |
| |<----------| "Drawing a Circle" |
| | | |
+----------------+ +--------------------+
+----------------+ +-----------------------+
| Rectangle | | DrawingVisitor |
+----------------+ +-----------------------+
| | | |
| accept() |---------->| visit(Rectangle) |
| | | |
| |<----------| "Drawing a Rectangle" |
| | | |
+----------------+ +-----------------------+
サンプル2
// Acceptorインターフェース
interface LogAcceptor {
void accept(LogVisitor visitor);
}
// 具体的なAcceptorクラス
class InfoLog implements LogAcceptor {
private String message;
public InfoLog(String message) {
this.message = message;
}
@Override
public void accept(LogVisitor visitor) {
visitor.visit(this);
}
public String getMessage() {
return message;
}
}
class WarningLog implements LogAcceptor {
private String message;
public WarningLog(String message) {
this.message = message;
}
@Override
public void accept(LogVisitor visitor) {
visitor.visit(this);
}
public String getMessage() {
return message;
}
}
class ErrorLog implements LogAcceptor {
private String message;
public ErrorLog(String message) {
this.message = message;
}
@Override
public void accept(LogVisitor visitor) {
visitor.visit(this);
}
public String getMessage() {
return message;
}
}
// Visitorインターフェース
interface LogVisitor {
void visit(InfoLog infoLog);
void visit(WarningLog warningLog);
void visit(ErrorLog errorLog);
}
// 具体的なVisitorクラス
class ConsoleLogVisitor implements LogVisitor {
@Override
public void visit(InfoLog infoLog) {
System.out.println("INFO: " + infoLog.getMessage());
}
@Override
public void visit(WarningLog warningLog) {
System.out.println("WARNING: " + warningLog.getMessage());
}
@Override
public void visit(ErrorLog errorLog) {
System.out.println("ERROR: " + errorLog.getMessage());
}
}
// メインクラス
public class VisitorPatternLogExample {
public static void main(String[] args) {
LogAcceptor infoLog = new InfoLog("This is an info message.");
LogAcceptor warningLog = new WarningLog("This is a warning message.");
LogAcceptor errorLog = new ErrorLog("This is an error message.");
LogVisitor consoleLogVisitor = new ConsoleLogVisitor();
infoLog.accept(consoleLogVisitor); // "INFO: This is an info message."
warningLog.accept(consoleLogVisitor); // "WARNING: This is a warning message."
errorLog.accept(consoleLogVisitor); // "ERROR: This is an error message."
}
}
-
LogAcceptor
インターフェース:
このメソッは、Visitor
を受け入れるために使用される。
accept(LogVisitor visitor)
メソッドを持ち、Visitorを受け入れる役割を果たしている。 -
具体的な
Acceptor
クラス:-
InfoLog
: 情報ログメッセージを表す。 -
WarningLog
: 警告ログメッセージを表す。 -
ErrorLog
: エラーログメッセージを表す。
-
各クラスは、LogAcceptor
インターフェースを実装し、accept
メソッドをオーバーライドしている。
-
LogVisitor
インターフェース:
各ログメッセージの種類に対するvisit
メソッドを持っている。 -
ConsoleLogVisitor
クラス:
LogVisitor
インターフェースを実装し、各ログメッセージの処理方法を定義している。
ここでは、コンソールにメッセージを出力するという処理方法を定義している。 -
VisitorPatternLogExample
クラス:
メインメソッドを持ち、ログメッセージを作成し、Visitor
を使用してそれらを処理する。
+-------------------+ +---------------------+
| LogAcceptor |<>--------| LogVisitor |
+-------------------+ +---------------------+
| + accept(visitor) | | + visit(infoLog) |
+-------------------+ | + visit(warningLog) |
| + visit(errorLog) |
+---------------------+
^
|
|
+---------------------+---------------------+
| | |
+----------------+ +----------------+ +----------------+
| InfoLog | | WarningLog | | ErrorLog |
+----------------+ +----------------+ +----------------+
| - message | | - message | | - message |
| + accept() | | + accept() | | + accept() |
| + getMessage() | | + getMessage() | | + getMessage() |
+----------------+ +----------------+ +----------------+
+----------------+ +---------------------+
| InfoLog | | ConsoleLogVisitor |
+----------------+ +---------------------+
| | | |
| accept() |----------> visit(InfoLog) |
| | | |
| |<---------| "INFO: ..." |
+----------------+ +---------------------+
+----------------+ +---------------------+
| WarningLog | | ConsoleLogVisitor |
+----------------+ +---------------------+
| | | |
| accept() |----------> visit(WarningLog) |
| | | |
| |<---------| "WARNING: ..." |
+----------------+ +---------------------+
+----------------+ +---------------------+
| ErrorLog | | ConsoleLogVisitor |
+----------------+ +---------------------+
| | | |
| accept() |----------> visit(ErrorLog) |
| | | |
| |<---------| "ERROR: ..." |
+----------------+ +---------------------+
Discussion