访问者模式
访问者模式属于行为模式。
访问者模式中属于相对比较复杂的一类,它会在A中让B访问,而实际在B中实际调用的是A的方法.
class A {
public void method1(){
System.out.println("AAAAAA");
}
public void method2(B b){
b.showA(this);
}
}
class B {
public void showA(A a){
a.method1();
}
}
A a = new A();
a.method1();
a.method2(new B());
这样的例子就是一个简单的访问者模式,但是还没有表达清楚访问者的含义。
访问者模式主要用于数据结构相对稳定的情况下,将数据的后续使用操作与数据结构进行分离。
例如:
电商项目中,在每一笔订单的资金方面的收支情况,资金的收支作为一个数据结构是不会改变的。
而对于资金的情况,财务会对其进行了解,了解的过程财务就是一个访问者,而访问者不仅局限于财务
作为公司的大BOSS也可以对其访问了解情况.(访问者的变化)
而财务了解的是每一单的资金状况,BOSS了解的直接是总体资金状态(数据操作的使用变化)
使用场景
- 使用的对象结构中的对象变动很小,并且要在其基础上进行新的操作
- 对象中存在重复代码操作,可以将其封装
- 对对象结构中的对象进行不同的数据操作,同事保证在不增加新的操作时修改这些类
代码示例
(一)允许访问者访问的接口
public interface Capital {
//允许的访问者
void accept(Visitor visitor);
}
(二)访问者访问的数据内容接口
public interface Visitor {
//查看收入
void readIncomeCapital(IncomeCapital incomeCapital);
//查看支出
void readExpenditureCapital(ExpenditureCapital expenditureCapital);
}
(三)资金的收入支出标识
public class VisitConfig {
public static final String INCOME="income";//收入
public static final String EXPENDITUR="expenditure";//收入
}
(四)资金的收入状况
public class IncomeCapital implements Capital {
private String status;//订单的标记 支出还是收入
private double price;//金钱
public IncomeCapital() {
}
public IncomeCapital(String status, double price) {
this.status = status;
this.price = price;
}
@Override
public void accept(Visitor visitor) {
visitor.readIncomeCapital(this);
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
(五)资金的支出情况
public class ExpenditureCapital implements Capital {
private String status;//订单的标记 支出还是收入
private double price;//金钱
public ExpenditureCapital() {
}
public ExpenditureCapital(String status, double price) {
this.status = status;
this.price = price;
}
@Override
public void accept(Visitor visitor) {
visitor.readExpenditureCapital(this);
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
(六)财务访问每一单的资金
public class FinanceVisitor implements Visitor {
private int position;//第几个订单
@Override
public void readIncomeCapital(IncomeCapital incomeCapital) {
position++;
if(incomeCapital.getStatus().equals(VisitConfig.INCOME)){
System.out.println("\n"+"第" + position + "个订单收入:" + incomeCapital.getPrice());
}
}
@Override
public void readExpenditureCapital(ExpenditureCapital expenditureCapital) {
if(expenditureCapital.getStatus().equals(VisitConfig.EXPENDITUR)){
System.out.println("\n"+"第" + position + "个订单支出:" + expenditureCapital.getPrice());
}
}
}
(七)BOSS访问所有的资金状况
public class BossVistor implements Visitor {
private double totalIncomeCapital;//总收入
private double totalExpenditureCapital;//总支出
@Override
public void readIncomeCapital(IncomeCapital incomeCapital) {
totalIncomeCapital=totalIncomeCapital+incomeCapital.getPrice();
}
@Override
public void readExpenditureCapital(ExpenditureCapital expenditureCapital) {
totalExpenditureCapital=totalExpenditureCapital+expenditureCapital.getPrice();
}
public void showIncomeCapital(){
System.out.print("\n"+"一共收入资金:"+totalIncomeCapital);
}
public void showExpenditureCapital(){
System.out.print("\n"+"一共支出资金:"+totalExpenditureCapital);
}
}
(八)资金管理统计添加
public class CapitalNote {
private List<Capital> capitals=new ArrayList<>();
//添加资金的收入和支出
public void add(Capital capital){
capitals.add(capital);
}
//添加访问者
public void acceptVistor(Visitor visitor){
for (Capital capital : capitals){
capital.accept(visitor);
}
}
}
调用方式
//第一单
IncomeCapital capital1=new IncomeCapital(VisitConfig.INCOME,1000);//收入1000
ExpenditureCapital capital2=new ExpenditureCapital(VisitConfig.EXPENDITUR,1000);//支出1000
//第二单
IncomeCapital capital3=new IncomeCapital(VisitConfig.INCOME,5000);//收入1000
ExpenditureCapital capital4=new ExpenditureCapital(VisitConfig.EXPENDITUR,1000);//支出1000
//添加账单
CapitalNote capitalNote=new CapitalNote();
capitalNote.add(capital1);
capitalNote.add(capital2);
capitalNote.add(capital3);
capitalNote.add(capital4);
//财务和BOSS访问
BossVistor bossVistor=new BossVistor();
FinanceVisitor financeVisitor=new FinanceVisitor();
capitalNote.acceptVistor(bossVistor);
capitalNote.acceptVistor(financeVisitor);
//总消费状态
bossVistor.showIncomeCapital();
bossVistor.showExpenditureCapital();
显示结果
第1个订单收入:1000.0
第1个订单支出:1000.0
第2个订单收入:5000.0
第2个订单支出:1000.0
一共收入资金:6000.0
一共支出资金:2000.0
将所有的统计收支状况就行了计算显示. 如果有其他的需求按照此案例进行单独的修改即可(如纯利润等等)
总结
- 优点
- 数据结构与数据内容隔离,针对业务变化操作数据内容而不会影响数据结构
- 封装的操作方法如果有变化或者拓展可以在不改变原本结构的状态下进行拓展增强
- 将访问者与被访问者完全隔离
- 缺点
- 访问者可以了解到具体的元素对象
- 如果有新增的元素类,都需要修改访问者很麻烦
- 在使用过程中并没有将对象抽象而使用了具体的对象,修改不便
因此,访问者模式适用于中后期的二次维护开发,在数据结构不变的情况下进行项目重构