[设计模式]访问者模式
1.参考了这边文章,个人觉得访问者模式不是非常适用,它提高了代码复杂度,而且对容器和访问业务两边都有入侵行为(通过接口)。对于单一访问者的需求,直接对容器进行遍历操作可能更好,或者直接在容器上提供方法,而不是给访问者提供接口。在需要使用多个访问者且容器的元素基本不变的情况下,访问者模式才是比较适用的。
2.Java 8 Stream 流特性是依据访问者模式实现的。
3.以下是个人学习时写的一个例子:
1.接口一:抽象访问者行为:
package com.xdsux.java.visitor; public interface InfoViewer { void view(ManVIP vipInfo); void view(WomanVIP vipInfo); }
因为容器的元素有两种,针对两种元素有不同的行为,所有有方法重载。
2.接口二:抽象元素提供访问者信息的行为。
package com.xdsux.java.visitor; public interface VIPInfo { //元素需要继承的接口,向访问者展示信息 void showInfo(InfoViewer viewer); }
容器中的元素实现该接口,访问者作为参数传入,元素将自身信息暴露给访问者(项目开发中,这里元素的信息对外暴露了,并不安全,当然也可以再次之上进一步优化):
package com.xdsux.java.visitor; public class ManVIP implements VIPInfo { private int age; private int income; public ManVIP(int age, int income) { this.age = age; this.income = income; } @Override public void showInfo(InfoViewer viewer) { // TODO Auto-generated method stub viewer.view(this); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getIncome() { return income; } public void setIncome(int income) { this.income = income; } }
WomenVIP.java代码和ManVIP.java一样。
3.容器类,容纳元素,并提供让访问者遍历元素的方法:
package com.xdsux.java.visitor; import java.util.ArrayList; import java.util.List; public class InfoCenter { private List<VIPInfo> ls = new ArrayList<>(); //用于加入会员信息 public void add(VIPInfo vip) { this.ls.add(vip); } //向访问者提供会员信息 public void show(InfoViewer viewer) { for(VIPInfo vip : ls) { //每个元素展示自己的信息 vip.showInfo(viewer); } } }
4.访问者实现类:VisitorA 实现访问者接口。
定义访问元素时的行为,如果有不同的访问行为,可以定义多个访问者类。
package com.xdsux.java.visitor; public class VisitorA implements InfoViewer { private int countsMan; private int countsWoman; private int sumAge; private int sumIncome; @Override public void view(ManVIP vipInfo) { //visitor只关心男会员的收入 this.sumIncome += vipInfo.getIncome(); this.countsMan++; } @Override public void view(WomanVIP vipInfo) { //visitor只关心女会员的年龄 this.sumAge += vipInfo.getAge(); this.countsWoman++; } public void showVisitorInfo() { System.out.println("男会员总人数: " + this.countsMan); System.out.println("平均收入: " + this.sumIncome/this.countsMan); System.out.println("女会员总人数: " + this.countsWoman); System.out.println("平均年龄: " + this.sumAge/this.countsWoman); } }
测试:
package com.xdsux.java.visitor; public class Client { public static void main(String[] args) { //创建容器类实例 InfoCenter ic = new InfoCenter(); //在容器中载入不同元素 ic.add(new ManVIP(32, 17000)); ic.add(new ManVIP(32, 18000)); ic.add(new ManVIP(32, 20000)); ic.add(new WomanVIP(32, 17000)); ic.add(new WomanVIP(22, 17000)); ic.add(new WomanVIP(27, 17000)); ic.add(new WomanVIP(26, 17000)); //创建访问者 VisitorA va = new VisitorA(); //访问者访问容器实例下的元素。并执行各自的操作 ic.show(va); va.showVisitorInfo(); } }
输出:
男会员总人数: 3
平均收入: 18333
女会员总人数: 4
平均年龄: 26