当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。
示例—营养成分
餐厅的菜单中除了显示除了显示菜单、菜单项以及原料外,客户要求每当顾客询问营养信息时,在不破坏原结构的情况下,需要把具体某项的营养信息显示出来。还要保证以后扩展起来比较方便,不用每次扩展都添加许多新方法。
UML图表示
代码演示
菜单抽象类
package Visitor;
import java.util.Iterator;
public abstract class MenuComponent {
private String name;
public MenuComponent(String name){
this.name = name;
}
public void add(MenuComponent menuComponent){
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent){
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i){
throw new UnsupportedOperationException();
}
public void print(){
throw new UnsupportedOperationException();
}
public Iterator createIterator(){
throw new UnsupportedOperationException();
}
public void getState(Visitor visitor){
visitor.getHealthRating(this);
visitor.getCalories(this);
visitor.getProtein(this);
visitor.getCarbs(this);
}
public abstract MenuComponent getMenu(String name);
public String getName(){
return name;
}
}
菜单项类
package Visitor;
import java.util.Iterator;
public class MenuItem extends MenuComponent {
public MenuItem(String name){
super(name);
}
@Override
public String toString() {
return getName();
}
@Override
public void print() {
System.out.print(" " + getName());
}
@Override
public Iterator createIterator() {
return new NullIterator();
}
@Override
public MenuComponent getMenu(String name) {
if (name == getName()) return this;
return null;
}
}
菜单类
package Visitor;
import java.util.ArrayList;
import java.util.Iterator;
public class Menu extends MenuComponent {
ArrayList menuComponents = new ArrayList();
public Menu(String name){
super(name);
}
@Override
public void add(MenuComponent menuComponent){
menuComponents.add(menuComponent);
}
@Override
public void remove(MenuComponent menuComponent){
menuComponents.remove(menuComponent);
}
@Override
public MenuComponent getChild(int i) {
return (MenuComponent)menuComponents.get(i);
}
@Override
public void print() {
System.out.print("\n" + getName());
System.out.print(": ");
Iterator iterator = menuComponents.iterator();
while (iterator.hasNext()){
MenuComponent menuComponent = iterator.next();
menuComponent.print();
}
}
@Override
public Iterator createIterator() {
return new CompositeIterator(menuComponents.iterator());
}
@Override
public MenuComponent getMenu(String name) {
Iterator iterator = menuComponents.iterator();
if (name == getName()) return this;
while (iterator.hasNext()){
MenuComponent menuComponent = iterator.next();
MenuComponent menu = menuComponent.getMenu(name);
if (menu != null){
return menu;
}
}
return null;
}
}
自定义迭代器
package Visitor;
import TreeMenu.Menu;
import TreeMenu.MenuComponent;
import java.util.Iterator;
import java.util.Stack;
public class CompositeIterator implements Iterator {
Stack stack = new Stack();
public CompositeIterator(Iterator iterator){
stack.push(iterator);
}
@Override
public boolean hasNext() {
if (stack.empty()){
return false;
}
else {
Iterator iterator = (Iterator) stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
}
else{
return true;
}
}
}
@Override
public Object next() {
if (hasNext()){
Iterator iterator = (Iterator) stack.peek();
MenuComponent component = (MenuComponent) iterator.next();
if (component instanceof Menu){
stack.push(component.createIterator());
}
return component;
}
else{
return null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
空迭代器
package Visitor;
import java.util.Iterator;
public class NullIterator implements Iterator {
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
访问类
package Visitor;
import java.util.Random;
public class Visitor {
Random random = new Random(47);
public void getHealthRating(MenuComponent menuComponent) {
System.out.println("HealthRating of " + menuComponent.getName() + " is " + random.nextInt(10) + ". ");
}
public void getCalories(MenuComponent menuComponent) {
System.out.println("Calories of " + menuComponent.getName() + " is " + random.nextInt(2000) + ". ");
}
public void getProtein(MenuComponent menuComponent) {
System.out.println("Protein of " + menuComponent.getName() + " is " + random.nextInt(100) + ". ");
}
public void getCarbs(MenuComponent menuComponent) {
System.out.println("Carbs of " + menuComponent.getName() + " is " + random.nextInt(200) + ". ");
}
}
服务员类
package Visitor;
public class Waitress {
MenuComponent allMenus;
Visitor visitor;
public Waitress(MenuComponent allMenus){
this.allMenus = allMenus;
this.visitor = new Visitor();
}
public void printMenu(){
allMenus.print();
}
public void showNutrient(String name){
if (allMenus != null){
MenuComponent menuComponent = allMenus.getMenu(name);
if (menuComponent != null){
menuComponent.getState(visitor);
}
}
}
}
测试代码
package Visitor;
public class VisitorDriver {
public static void main(String[] args) {
MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU");
MenuComponent dinerMenu = new Menu("DINER MENU");
MenuComponent allMenus = new Menu("All MENUS");
allMenus.add(pancakeHouseMenu);
allMenus.add(dinerMenu);
MenuComponent d1 = new Menu("Vegetarian BLT");
MenuComponent d11 = new MenuItem("Bacon");
MenuComponent d12 = new MenuItem("Lettuce");
MenuComponent d13 = new MenuItem("Tomato");
MenuComponent d14 = new MenuItem("Wheat");
d1.add(d11);
d1.add(d12);
d1.add(d13);
d1.add(d14);
MenuComponent d2 = new Menu("Soup of the day");
MenuComponent d21 = new MenuItem("Tomato");
MenuComponent d22 = new MenuItem("Potato");
d2.add(d21);
d2.add(d22);
dinerMenu.add(d1);
dinerMenu.add(d2);
MenuComponent p1 = new Menu("K&B's Pancake Breakfast");
MenuComponent p11 = new MenuItem("Pancakes");
MenuComponent p12 = new MenuItem("Eggs");
MenuComponent p13 = new MenuItem("Toast");
p1.add(p11);
p1.add(p12);
p1.add(p13);
MenuComponent p2 = new Menu("Waffles");
MenuComponent p21 = new MenuItem("Waffles");
MenuComponent p22 = new MenuItem("Blueberries");
p2.add(p21);
p2.add(p22);
pancakeHouseMenu.add(p1);
pancakeHouseMenu.add(p2);
Waitress waitress = new Waitress(allMenus);
waitress.printMenu();
System.out.println();
System.out.println("-------------------------");
waitress.showNutrient("Vegetarian BLT");
System.out.println("-------------------------");
waitress.showNutrient("Blueberries");
}
}
测试结果
All MENUS:
PANCAKE HOUSE MENU:
K&B's Pancake Breakfast: Pancakes Eggs Toast
Waffles: Waffles Blueberries
DINER MENU:
Vegetarian BLT: Bacon Lettuce Tomato Wheat
Soup of the day: Tomato Potato
-------------------------
HealthRating of Vegetarian BLT is 8.
Calories of Vegetarian BLT is 555.
Protein of Vegetarian BLT is 93.
Carbs of Vegetarian BLT is 61.
-------------------------
HealthRating of Blueberries is 1.
Calories of Blueberries is 429.
Protein of Blueberries is 68.
Carbs of Blueberries is 0.