访问者模式

访问者模式Visitor Pattern中属于行为型模式,针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法,元素的执行算法可以随着访问者改变而改变,主要意图在于将数据结构与数据操作分离,解决稳定的数据结构和易变的操作耦合问题。

描述

在面向对象编程和软件工程中,访问者设计模式是一种将算法与它所运行的对象结构分离的方法,这种分离的实际结果是能够在不修改现有对象结构的情况下向现有对象结构添加新操作,这是遵循开放封闭原则的一种方式。

优点

  • 符合单一职责原则,凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
  • 扩展性良好,元素类可以通过接受不同的访问者来实现对不同操作的扩展。

缺点

  • 具体元素对访问者公布细节,违反了迪米特原则。
  • 具体元素变更比较困难。
  • 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

适用环境

  • 假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
  • 假如一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。

实现

// 以动物园模拟为例,我们有几种不同种类的动物,它们能够发出不同的声音。

class Monkey {
    shout() {
        console.log("Ooh oo aa aa!");
    }

    accept(operation) {
        operation.visitMonkey(this);
    }
}

class Lion {
    roar() {
        console.log("Roaaar!");
    }

    accept(operation) {
        operation.visitLion(this);
    }
}

class Dolphin {
    speak() {
        console.log("Tuut tuttu tuutt!");
    }

    accept(operation) {
        operation.visitDolphin(this);
    }
}

const speak = {
    visitMonkey(monkey) {
        monkey.shout();
    },
    visitLion(lion) {
        lion.roar();
    },
    visitDolphin(dolphin) {
        dolphin.speak();
    }
}

;(function(){
    const monkey = new Monkey();
    const lion = new Lion();
    const dolphin = new Dolphin();

    monkey.accept(speak);    // Ooh oo aa aa!    
    lion.accept(speak);      // Roaaar!
    dolphin.accept(speak);   // Tuut tutt tuutt!
})();


// 我们可以通过对动物具有继承层次结构来简单地做到这一点
// 但是每当必须向动物添加新动作时,我们就必须修改动物。
// 而现在我们不必更改它们。
// 例如,假设我们被要求将跳跃行为添加到动物中,我们可以简单地通过创建一个新的访客来添加它。

const jump = {
    visitMonkey(monkey) {
        console.log("Jumped 20 feet high! on to the tree!");
    },
    visitLion(lion) {
        console.log("Jumped 7 feet! Back on the ground!");
    },
    visitDolphin(dolphin) {
        console.log("Walked on water a little and disappeared");
    }
}

;(function(){
    const monkey = new Monkey();
    const lion = new Lion();
    const dolphin = new Dolphin();

    monkey.accept(speak);   // Ooh oo aa aa!
    monkey.accept(jump);    // Jumped 20 feet high! on to the tree!

    lion.accept(speak);     // Roaaar!
    lion.accept(jump);      // Jumped 7 feet! Back on the ground! 

    dolphin.accept(speak);  // Tuut tutt tuutt! 
    dolphin.accept(jump);   // Walked on water a little and disappeared
})();

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://www.runoob.com/design-pattern/visitor-pattern.html https://github.com/sohamkamani/javascript-design-patterns-for-humans#-visitor https://www.bookstack.cn/read/design-pattern-in-javascript/design-pattern-visitor-pattern-README.md