设计模式_24:访问者模式

书上的原句:

访问者模式:表示一个作用在某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

一个例子:我们先用最简单的多态来实现一个动物的行为:

public class Main {

    public static void main(String[] args) {

        Animal bird = new Bird();
        bird.setState("flying");
        bird.action();
        bird.setState("eating");
        bird.action();


        Animal bat = new Bat();
        bat.setState("eating");
        bat.action();
        bat.setState("flying");
        bat.action();

    }
}

abstract class Animal {

    protected String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    abstract void action();
}

class Bird extends Animal {
    @Override
    void action() {
        if ("flying".equals(state)){
            System.out.println("Bird flying");
        }
        else if ("eating".equals(state)){
            System.out.println("Bird eating");
        }
    }
}

class Bat extends Animal {
    @Override
    void action() {
        if ("flying".equals(state)){
            System.out.println("Bat flying");
        }
        else if ("eating".equals(state)){
            System.out.println("Bat eating");
        }
    }
}
运行结果:

Bird flying
Bird eating
Bat eating
Bat flying
如果需要为动物类添加一个playing的动作,就必须改动 Animal、Bird、Bat三个类,不符合开闭原则,可以用访问者模式来改进:


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

public class Main {

    public static void main(String[] args) {

        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.attach(new Bird());
        objectStructure.attach(new Bat());
        objectStructure.display(new FlyAction());
        objectStructure.display(new EatAction());
        objectStructure.display(new PlayAction());
    }
}

//对象结构
class ObjectStructure {

    List<Animal> list = new ArrayList<>();

    //添加动物
    public void attach(Animal animal){
        list.add(animal);
    }

    //删除动物
    public void detach(Animal animal){
        list.remove(animal);
    }

    //依次用action访问各个对象
    public void display(Action action){
        for (Animal animal : list){
            animal.accept(action);
        }
    }

}

//抽象visitor访问者
abstract class Action {
    abstract void doBirdAction(Bird bird);
    abstract void doBatAction(Bat bat);
}

class FlyAction extends Action {
    @Override
    void doBirdAction(Bird bird) {
        System.out.println(bird.getClass().getSimpleName() + " flying");
    }

    @Override
    void doBatAction(Bat bat) {
        System.out.println(bat.getClass().getSimpleName() + " flying");
    }
}

class EatAction extends Action {
    @Override
    void doBirdAction(Bird bird) {
        System.out.println(bird.getClass().getSimpleName() + " eating");
    }

    @Override
    void doBatAction(Bat bat) {
        System.out.println(bat.getClass().getSimpleName() + " eating");
    }
}

//这时只需要再添加一个PlayAction就可以了,完全符合开闭原则
class PlayAction extends Action {
    @Override
    void doBirdAction(Bird bird) {
        System.out.println(bird.getClass().getSimpleName() + " playing");
    }

    @Override
    void doBatAction(Bat bat) {
        System.out.println(bat.getClass().getSimpleName() + " playing");
    }
}

abstract class Animal {
    //让动物接受一个行为
    abstract void accept(Action action);
}

class Bird extends Animal {
    @Override
    void accept(Action action) {
        action.doBirdAction(this);
    }
}

class Bat extends Animal {
    @Override
    void accept(Action action) {
        action.doBatAction(this);
    }
}
运行结果:

Bird flying
Bat flying
Bird eating
Bat eating
Bird playing
Bat playing

但访问者模式也有局限性:设计之初被访问类的数量必须是确定的,例如上述的Bird和Bat,如果突然要另外加入一个Dragon类,那么各个Action类就要相应地加上一个doDragonAction的方法了,这种情况下也不符合开闭原则,而且Action类比较多的情况下,修改会更加的繁杂。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值