访问者模式

想要为一个对象增强新的行为,且不封装具体的实现,那么就用访问者模式

一般我们都是使用访问者模式增添遍历行为,这是一个误区。

模型

访问者模式_第1张图片

  • Element 表示要增强的行为,即accept方法
  • elementA 代表原有对象
  • visitor表示抽象接口
  • visitorA表示具体的行为实现

改进之前的例子

组合模式中的列子:https://blog.csdn.net/dengjili/article/details/79705777

这是一家餐厅的菜单结构,现在我们需要将其遍历输出
访问者模式_第2张图片

原模型设计

访问者模式_第3张图片

更改模型设计

访问者模式_第4张图片

基类代码

package headfirst.hd.visitor.eg;

public interface Element {
	void accept(Visitor visitor);
}


package headfirst.hd.visitor.eg;

public abstract class Component implements Element{
	// 集合操作-增
    public void add(Component menuComponent) {
        throw new UnsupportedOperationException();
    }

    // 集合操作-删
    public void remove(Component menuComponent) {
        throw new UnsupportedOperationException();
    }

    // 集合操作-查
    public Component getChild(int i) {
        throw new UnsupportedOperationException();
    }

    public String getName() {
        throw new UnsupportedOperationException();
    }

    public float getPrice() {
        throw new UnsupportedOperationException();
    }

    public void print(int offset) {
        throw new UnsupportedOperationException();
    }
    
}

菜单项

package headfirst.hd.visitor.eg;

//菜单项
public class Item extends Component {
	private String name;
	private float price;

	public Item(String name, float price) {
		this.name = name;
		this.price = price;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public float getPrice() {
		return price;
	}

	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
}

组合菜单

package headfirst.hd.visitor.eg;

import java.util.ArrayList;
import java.util.List;

public class Menu extends Component {

    List menuComponents = new ArrayList();
    String name;
    String description;

    public Menu(String name, String description) {
        this.name = name;
        this.description = description;
    }
    @Override
    public void add(Component menuComponent) {
        menuComponents.add(menuComponent);
    }
    @Override
    public void remove(Component menuComponent) {
        menuComponents.remove(menuComponent);
    }
    @Override
    public Component getChild(int i) {
        return menuComponents.get(i);
    }

    @Override
    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }
    
    public List getMenuComponents() {
		return menuComponents;
	}

	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

}

访问者类

package headfirst.hd.visitor.eg;

public interface Visitor {
	void visit(Element e);
}

package headfirst.hd.visitor.eg;

public class ItemVisitor implements Visitor {

	@Override
	public void visit(Element e) {
		
		if (e instanceof Item) {
			Item item = (Item) e;
			System.out.println("[商品名=" + item.getName() + ", 价格=" + item.getPrice() + "]");
		}
	}

}

package headfirst.hd.visitor.eg;

import java.util.List;

public class MenuVisitor implements Visitor {

	@Override
	public void visit(Element e) {
		if (Menu.class.isAssignableFrom(e.getClass())) {
			Menu item = (Menu) e;
			System.out.println("{菜单名=" + item.getName() + ", 描述=" + item.getDescription() + "}");
			// 遍历子节点
			List menuComponents = item.getMenuComponents();
			for (Component component : menuComponents) {
				if (Menu.class.isAssignableFrom(component.getClass())) {
					component.accept(this);
				} else {
					component.accept(new ItemVisitor());
				}
			}
		}
	}

}

客户端类

package headfirst.hd.visitor.eg;

public class Waitress {
	Component menu;

	public Waitress(Component menu) {
		this.menu = menu;
	}

	// 遍历方法
	public void printMenu(Visitor visitor) {
		menu.accept(visitor);
	}
}

测试类

package headfirst.hd.visitor.eg;

public class DriveTest {

	public static void main(String[] args) {
        Component menu = simpleFactory();
        Waitress waitress = new Waitress(menu);
        //打印菜单
        waitress.printMenu(new MenuVisitor());
    }

    //创建一份菜单
    private static Component simpleFactory() {
        //菜单
        Component menu = new Menu("菜单", "xxx饭店菜单");

        //菜单项
        Component menuA = new Menu("饭类", "类别:主食类");
        Component menuB = new Menu("水类", "类别:补充水分");
        Component menuC = new Menu("小吃类", "类别:零食");
        Component menuD = new Menu("汤类", "类别:水类的子类");
        menu.add(menuA);
        menu.add(menuB);
        menu.add(menuC);

        //菜单项中具体类别
        Component itemA1 = new Item("牛肉", 15f);
        Component itemA2 = new Item("鸡肉", 13f);
        Component itemA3 = new Item("鸭肉", 14f);
        menuA.add(itemA1);
        menuA.add(itemA2);
        menuA.add(itemA3);

        Component itemB1 = new Item("红茶", 4f);
        Component itemB2 = new Item("奶茶", 6f);
        menuB.add(itemB1);
        menuB.add(itemB2);
        menuB.add(menuD);   //菜单项的包含

        Component itemC1 = new Item("烤翅", 8f);
        Component itemC2 = new Item("尾虾", 8f);
        Component itemC3 = new Item("鱿鱼", 5f);
        menuC.add(itemC1);
        menuC.add(itemC2);
        menuC.add(itemC3);

        Component itemD1 = new Item("菜汤", 6f);
        Component itemD2 = new Item("酸汤", 6f);
        Component itemD3 = new Item("其他汤", 5f);
        menuD.add(itemD1);
        menuD.add(itemD2);
        menuD.add(itemD3);

        return menu;
    }
}

测试结果

{菜单名=菜单, 描述=xxx饭店菜单}
{菜单名=饭类, 描述=类别:主食类}
[商品名=牛肉, 价格=15.0]
[商品名=鸡肉, 价格=13.0]
[商品名=鸭肉, 价格=14.0]
{菜单名=水类, 描述=类别:补充水分}
[商品名=红茶, 价格=4.0]
[商品名=奶茶, 价格=6.0]
{菜单名=汤类, 描述=类别:水类的子类}
[商品名=菜汤, 价格=6.0]
[商品名=酸汤, 价格=6.0]
[商品名=其他汤, 价格=5.0]
{菜单名=小吃类, 描述=类别:零食}
[商品名=烤翅, 价格=8.0]
[商品名=尾虾, 价格=8.0]
[商品名=鱿鱼, 价格=5.0]

结论

访问者模式增添行为,但是不提供具体的实现,访问者模式=遍历,错误!!!

jdk使用访问者模式

Java8 新特性之集合: forEach(Consumer action)

你可能感兴趣的:(设计模式,设计模式)