设计模式之访问者模式

Posted ProChick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之访问者模式相关的知识,希望对你有一定的参考价值。

1.简要概述

  • 访问者模式属于行为型设计模式,在类的内部结构不变的情况下,不同的访问者访问某个对象会呈现出不同的处理结果。
  • 访问者模式就是封装一些作用于某种数据结构的各个元素的操作,然后它可以在不改变数据结构的前提下,定义作用于这些元素的新操作。
  • 访问者模式的核心就是为一个对象结构增加新的能力,在被访问的类里面加一个对外提供接待访问者的接口。
  • 访问者模式主要就是将数据结构和数据操作进行分离,解决了数据结构和数据操作的耦合性问题。

2.模式结构

👉通常由一个访问者抽象类( 负责为对象结构中的每一个Element元素都定义一个访问接口 ),多个具体的访问者类( 负责为对象结构中的每一个Element元素都实现一个访问的具体内部逻辑 ),一个元素抽象类( 负责定义所有元素的公共方法接口 ),多个具体的元素类( 负责提供一个具体的方法实现,完成对访问者对象的接收 ),一个对象结构类( 负责管理和维护对象结构中所有的对象元素,并提供一个高层的接口,用来允许访问者访问对应的元素 ),一个客户类( 负责访问者类和对象结构类进行调用,完成对象结构中元素的访问操作)共同组成。

3.实现代码

举例 💡 :假设现在有一个歌唱比赛,每一个选手演唱完毕后,评委都会给该选手进行一个评价,评价有优秀和一般两种水平。如果我们想要在比赛后,统计男性评委和女性评委的评价情况,那么我们就可以采用观察者模式进行处理。

评价类(访问者抽象类)

public abstract class Evaluate{
    
    // 获取男性评委的评价
    public abstract void getMaleEvaluate(MaleJudge male);
    
    // 获取女性评委的评价
    public abstract void getFemaleEvaluate(FemaleJudge male);
}

优秀评价类(具体的访问者类)

public class ExcellentEvaluate extends Evaluate{
    
    @Override
    public abstract void getMaleEvaluate(MaleJudge male){
        System.out.println("男性评委:" + male.getName + "给出了优秀");
    }
    
    @Override
    public abstract void getFemaleEvaluate(FemaleJudge male){
        System.out.println("女性评委:" + male.getName + "给出了优秀");
    }
}

一般评价类(具体的访问者类)

public class GeneralEvaluate extends Evaluate{
    @Override
    public abstract void getMaleEvaluate(MaleJudge male){
        System.out.println("男性评委:" + male.getName + "给出了一般");
    }
    
    @Override
    public abstract void getFemaleEvaluate(FemaleJudge male){
        System.out.println("女性评委:" + male.getName + "给出了一般");
    }
}

评委类(元素抽象类)

public abstract class Judge{
    protected String name;
    
    public Judge(String name){
        this.name = name;
    }
    
    // 接收某个评价
    public abstract void accept(Evaluate evaluate);
    
    public String getName(){
        return this.name;
    }
}

男性评委类(具体元素类)

public class MaleJudge extends Judge{
    
    public MaleJudge(String name){
        super(name);
    }
    
    @Override
    public abstract void accept(Evaluate evaluate){
        evaluate.getMaleEvaluate(this);
    }
}

女性评委类(具体元素类)

public class FemaleJudge extends Judge{
    public FemaleJudge(String name){
        super(name);
    }
    
    @Override
    public abstract void accept(Evaluate evaluate){
        evaluate.getFemaleEvaluate(this);
    }
}

评委结构类(对象结构类)

public class JudgeStructure{
    private List<Judge> judges = new ArrayList<>();
    
    public void addJudge(Judge judge){
        judges.add(judge);
    }
    
    public void delJudge(Judge judge){
        judges.remove(judge);
    }
    
    // 获取所有评委评价信息
    public void displayAllEvaluate(Evaluate evaluate){
        for(Judge judge : judges){
            judge.accept(evaluate);
        }
    }
}

客户类

// 测试客户端
public class VisitorClient{
    public static void main(String[] args) {
        JudgeStructure js = new JudgeStructure();
        
        // 创建一个男性评委
        Judge judge1 = new MaleJudge("小刚"); 
        js.add(judge1);
        // 创建一个女性评委
        Judge judge2 = new FemaleJudge("小红");
        js.add(judge2);
        
        // 获取所有评委评价优秀的结果
        js.displayAllEvaluate(new ExcellentEvaluate());
        
        // 获取所有评委评价一般的结果
        js.displayAllEvaluate(new GeneralEvaluate());
    }
}

4.优点好处

  • 在访问者模式中,将数据结构和作用于结构上的操作进行了解耦合,使得操作集合可相对自由地演化,也使得算法操作增加变得非常容易。
  • 在访问者模式中,由于元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,所以访问者类的设计符合单一职责原则。
  • 在访问者模式中,由于被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展,所以具有良好的扩展性。
  • 在访问者模式中,可以通过访问者来定义整个对象结构通用的功能,从而提高了系统复用性。

5.缺点弊端

  • 在访问者模式中,访问者要访问某个元素就必然要求这个元素类公布一些方法和数据,也就是说访问者关注了每一个元素类内部的具体细节,这违反了迪米特法则。
  • 在访问者模式中,访问者依赖的是具体的元素,而不是抽象元素,违反了依赖倒置原则。
  • 在访问者模式中,由于具体的元素被访问者所依赖关联着,所以对于具体元素的变更就变得比较困难了,就需要修改对应的访问者内部逻辑,违反了开闭原则。

6.应用场景

  • 当我们需要对一个对象结构中的对象进行多种不同操作,同时需要避免这些不同操作之间的关联性的时候,就可以使用访问者模式。
  • 当系统中的某个对象结构包含很多类对象,它们又有不同的接口,而我们想对这些对象实施一些依赖于其具体类的操作的时候,就可以使用访问者模式。
  • 当我们定义的对象结构中的类很少改变,但经常又需要在此结构上动态的定义新的操作的时候,就可以使用访问者模式。
  • 当系统中存在比较稳定的数据结构,并且有经常变化的功能需求的时候,就可以使用访问者模式。
  • 当系统中某些数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。

以上是关于设计模式之访问者模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之观察者模式与访问者模式详解和应用

PHP面向对象之访问者模式+组合模式

设计模式之单例模式

设计模式之访问者模式

JAVA SCRIPT设计模式--行为型--设计模式之Vistor访问者(23)

JAVA SCRIPT设计模式--行为型--设计模式之Vistor访问者(23)