跟萌新一起学设计模式(十四)之访问者模式

**

设计模式(十四)之访问者模式

**

  • 案例说明

      我们有一家水果小店,现在老板想要做一个店内水果的评价系统,以三种水果——苹果、香蕉、芒果为例,评价等级有Nice、bad、SoSo,如果我们的水果种类越来越多,评价等级也越来越多,我们的用传统写法来做的话代码维护量就会倍增,所以我们可以用访问者模式来解决这个需求。

      访问者模式里面有几种角色——访问者、具体元素(行为、属性)、管理访问者和具体元素的接口(数据结构)。在外面的例子里面,水果是抽象的访问者,苹果、香蕉、芒果是具体的访问者,评价等级可以为抽象元素,Nice、bad、SoSo是具体的元素。先看一下类图:
    在这里插入图片描述
      Fruit中有一个抽象方法accept,参数接收Action;Apple、Banana、Mango继承了Fruit;Action包含了给Apple、Banana、Mango评价的三个抽象方法,也将Apple、Banana、Mango组合了进去;Nice、bad、SoSo继承了Action;ObjectStructure将Fruit和Action组合了进去,包含了一个集合用来添加、移除Fruit,还有选择味道评价的方法。

  Fruit抽象类

public abstract class Fruit {
    // 提供一个方法,让访问者可以访问
    public abstract void accept(Action action);
}

  Fruit的具体子类

public class Apple extends Fruit{
    @Override
    public void accept(Action action) {
        action.getAppleTaste(this);
    }
}
public class Banana extends Fruit{
    @Override
    public void accept(Action action) {
        action.getBananaTaste(this);
    }
}
public class Mango extends Fruit{
    @Override
    public void accept(Action action) {
        action.getMangoTaste(this);
    }
}

  抽象评价

public abstract class Action {
    // 评价苹果的味道
    public abstract void getAppleTaste(Apple apple);

    // 评价香蕉的味道
    public abstract void getBananaTaste(Banana banana);

    // 评价芒果的味道
    public abstract void getMangoTaste(Mango mango);
}

  具体的评价

public class Nice extends Action{
    @Override
    public void getAppleTaste(Apple apple) {
        System.out.println("苹果很好吃");
    }

    @Override
    public void getBananaTaste(Banana banana) {
        System.out.println("香蕉很好吃");
    }

    @Override
    public void getMangoTaste(Mango mango) {
        System.out.println("芒果很好吃");
    }
}
public class SoSo extends Action{
    @Override
    public void getAppleTaste(Apple apple) {
        System.out.println("苹果味道一般般");
    }

    @Override
    public void getBananaTaste(Banana banana) {
        System.out.println("香蕉味道一般般");
    }

    @Override
    public void getMangoTaste(Mango mango) {
        System.out.println("芒果味道一般般");
    }
}
public class Bad extends Action{
    @Override
    public void getAppleTaste(Apple apple) {
        System.out.println("苹果不好吃");
    }

    @Override
    public void getBananaTaste(Banana banana) {
        System.out.println("香蕉不好吃");
    }

    @Override
    public void getMangoTaste(Mango mango) {
        System.out.println("芒果不好吃");
    }
}

  评价队列

public class ObjectStructure {
    // 用来管理评价队列里面的水果
    private List<Fruit> fruits = new LinkedList<>();

    // 在评价队列里面添加一样水果
    public void add(Fruit fruit){
        fruits.add(fruit);
    }

    // 在评价队列里面移除一样水果
    public void remove(Fruit fruit){
        fruits.remove(fruit);
    }

    // 给评价队列里面的水果都选择同一种评价
    public void choose(Action action){
        for (Fruit fruit : fruits) {
            fruit.accept(action);
        }
    }
}

  客户端

public class Client {
    public static void main(String[] args) {
        // 拿到一个评价队列
        ObjectStructure os = new ObjectStructure();
        Apple apple = new Apple();
        // 在评价队列中加入苹果
        os.add(apple);
        // 给评价队列中的苹果选择好吃的评价
        os.choose(new Nice());
        // 在评价队列中移除苹果
        os.remove(apple);
        // 在评价队列中加入香蕉
        os.add(new Banana());
        // 在评价队列中加入芒果
        os.add(new Mango());
        // 给评价队列中的香蕉和芒果选择一般般的评价
        os.choose(new SoSo());
    }
}

  测试

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=56628:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar;D:\dev_tools\repository\cglib\cglib\3.3.0\cglib-3.3.0.jar;D:\dev_tools\repository\org\ow2\asm\asm\7.1\asm-7.1.jar com.wd.visitor.Client
苹果很好吃
香蕉味道一般般
芒果味道一般般

Process finished with exit code 0
  • 总结
      1、访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高;
      2、访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统;
      3、具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难;
      4、违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素;
      5、如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值