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

Posted 火柴盒zhang

tags:

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

         JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C++,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代表全部的正确,特此声明。若读者需要了解设原则、设计变化方向,环境相关等信息请查看设计模式开篇

        所有JAVA SCRIPT设计模式快捷连接:

              创建型:(1)  抽象工厂 (2) 生成器 (3) 工厂方法 (4) 原型  (5) 单例

              结构型:(6) 适配器  (7) 桥接  (8) 组合 (9) 装饰 (10) 外观 (11) 享元 (12) 代理​

              行为型:(13) ​职责链 (14) ​命令 (15) ​解释器 (16) ​迭代器 (17) ​中介者 (18) ​备忘录 (119) ​观察者 (20) ​状态​ (21) ​策略 (22) ​模板方法 (23) 访问者​


一、UML类图

参与者:  

1.1 Visitor(访问者,如NodeVisitor)

  • 为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。

1.2 ConcreteVisitor(具体访问者,如TypeCheckingVisitor)

  • 实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。

1.3 Element(元素,如Node)

  • 定义一个Accept操作,它以一个访问者为参数。

1.4 ConcreteElement(具体元素,如AssignmentNode,VariableRefNode)

  • 实现Accept操作,该操作以一个访问者为参数。

1.5 ObjectStructure(对象结构,如Program)

  • 能枚举它的元素。
  • 可以提供一个高层的接口以允许该访问者访问它的元素。
  • 可以是一个复合(参见Composite(4.3))或是一个集合,如一个列表或一个无序集合。

二、意图

    表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

     不变元素Node,不同Visitor访问这些元素Node不同的操作。

三、适用性 

  1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
  3. 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那 么可能还是在这些类中定义这些操作较好。

四、示例代码

4.1  动机

        考虑一个编译器,它将源程序表示为一个抽象语法树。该编译器需在抽象语法树上实施某些操作以进行“静态语义”分析,例如检查是否所有的变量都已经被定义了。它也需要生
成代码。因此它可能要定义许多操作以进行类型检查、代码优化、流程分析,检查变量是否在使用前被赋初值,等等。此外,还可使用抽象语法树进行优美格式打印、程序重构、代码植入以及对程序进行多种度量。

        这些操作大多要求对不同的节点进行不同的处理。例如对代表赋值语句的结点的处理就不同于对代表变量或算术表达式的结点的处理。因此有用于赋值语句的类,有用于变量访问的类,还有用于算术表达式的类,等等。结点类的集合当然依赖于被编译的语言,但对于一个给定的语言其变化不大。

         上面的框图显示了 Node类层次的一部分。这里的问题是,将所有这些操作分散到各种结点类中会导致整个系统难以理解、难以维护和修改。将类型检查代码与优美格式打印代码或流程分析代码放在一起,将产生混乱。此外,增加新的操作通常需要重新编译所有这些类。 如果可以独立地增加新的操作,并且使这些结点类独立于作用于其上的操作,将会更好一些。

         要实现上述两个目标,我们可以将每一个类中相关的操作包装在一个独立的对象(称为 一个Visitor)中,并在遍历抽象语法树时将此对象传递给当前访问的元素。当一个元素“accepts”该访问者时,该元素向访问者发送一个包含自身类信息的请求。该请求同时也将该元素本身作为一个参数。然后访问者将为该元素执行该操作—这一操作以前是在该元素的类中的。 例如,一个不使用访问者的编译器可能会通过在它的抽象语法树上调用 TypeCheck操作对一个过程进行类型检查。每一个结点将对调用它的成员的TypeCheck以实现自身的TypeCheck(参见前面的类框图)。如果该编译器使用访问者对一个过程进行类型检查,那么它将会创建一个TypeCheckingVisitor对象,并以这个对象为一个参数在抽象语法树上调用Accept操作。每一个结点在实现Accept时将会回调访问者:一个赋值结点调用访问者的VisitAssignment操作,而一个变量引用将调用VisitVariableReference。以前类AssignmentNode的TypeCheck操作现在成为TypeCheckingVisitor的VisitAssignment操作。

        为使访问者不仅仅只做类型检查,我们需要所有抽象语法树的访问者有一个抽象的父类NodeVisitor。NodeVisitor必须为每一个结点类定义一个操作。一个需要计算程序度量的应用
将定义NodeVisitor的新的子类,并且将不再需要在结点类中增加与特定应用相关的代码。Visitor模式将每一个编译步骤的操作封装在一个与该步骤相关的Visitor中(参见下图)。

        使用Visitor模式,必须定义两个类层次:一个对应于接受操作的元素(Node层次)另一个对应于定义对元素的操作的访问者(NodeVisitor层次)。给访问者类层次增加一个新的子类即可创建一个新的操作。只要该编译器接受的语法不改变(即不需要增加新的Node子类),我们就可以简单的定义新的NodeVisitor子类以增加新的功能。

4.2  目录结构:

4.3 Visitor(访问者,如NodeVisitor)

  • 为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。

import Node  from '../Node/Node.js';

export default  class NodeVisitor 

	constructor() 
			 
	
	 
	VisitAssignment(Node)
	
		 
	
	 
	VisitVariableRef(Node)
	
		 
	
	 

4.4 ConcreteVisitor(具体访问者,如TypeCheckingVisitor)

  • 实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。

import NodeVisitor  from '../NodeVisitor.js'; 
export default  class TypeCheckingVisitor extends NodeVisitor 
	
	constructor() 
		 super();
    
	VisitAssignment(AssignmentNode)
	
		  console.log(` TypeCheckingVisitor VisitAssignment `);
	
	 
	VisitVariableRef(VariableRefNode)
	
		  console.log(` TypeCheckingVisitor VisitVariableRef `);
	
	 


import NodeVisitor  from '../NodeVisitor.js'; 

export default  class CodeGeneratingVisitor extends NodeVisitor 
	
	constructor() 
		 super();
    
	VisitAssignment(AssignmentNode)
	
		   console.log(` CodeGeneratingVisitor VisitAssignment `);
	
	 
	VisitVariableRef(VariableRefNode)
	
		  console.log(` CodeGeneratingVisitor VisitVariableRef `);
	
	 

4.5 Element(元素,如Node)

  • 定义一个Accept操作,它以一个访问者为参数。

import NodeVisitor  from '../Visitor/NodeVisitor.js';

export default  class Node 
	 
    constructor( ) 
		 
    
    Accept(NodeVisitor)    
		 
    
	 
  

4.6 ConcreteElement(具体元素,如AssignmentNode,VariableRefNode)

  • 实现Accept操作,该操作以一个访问者为参数。
import Node  from '../Node.js'; 
 

export default  class AssignmentNode extends Node 
   name;
   type;
   value;
	constructor(name,type,value) 
	 super();
	 this.name=name;
	 this.type=type;
	 this.value=value;
	
   
	Accept(NodeVisitor) 
		NodeVisitor.VisitAssignment(this);
	
	 
   
import Node  from '../Node.js'; 
 

export default  class VariableRefNode extends Node 
  
	name;
	type;
	value;
		constructor(name,type,value) 
		 super();
		 this.name=name;
		 this.type=type;
		 this.value=value;
		
   
	Accept(NodeVisitor) 
		NodeVisitor.VisitVariableRef(this);
	
	 
   

4.7 ObjectStructure(对象结构,如Program)

  • 能枚举它的元素。
  • 可以提供一个高层的接口以允许该访问者访问它的元素。
  • 可以是一个复合(参见Composite(4.3))或是一个集合,如一个列表或一个无序集合。
import VariableRefNode from './Node/impl/VariableRefNode.js';
import AssignmentNode from './Node/impl/AssignmentNode.js';
import CodeGeneratingVisitor from './Visitor/impl/CodeGeneratingVisitor.js';
import TypeCheckingVisitor from './Visitor/impl/TypeCheckingVisitor.js';

export default class Program 
	 
	treeNode = []; //语法树 结果集
	constructor( ) 
		let varANode = new  AssignmentNode('aa', 'int', 9);
		this.treeNode.push(varANode);
		let refA =new VariableRefNode('bb', 'int', varANode);
		this.treeNode.push(refA);
		this.Accept(new TypeCheckingVisitor());
		this.Accept(new CodeGeneratingVisitor());
	
	Accept(visitor) 
		
		for (let n = 0; n < this.treeNode.length; n++) 
			let item = this.treeNode[n];
			item.Accept(visitor);
		
	
	

4.8  测试html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">


		<script type="module">
			import Program from './Program.js';
			 
			
			let cl = new Program();
			
		 
		</script>
	</head>
	<body>
		
	</body>
</html>

测试结果:

TypeCheckingVisitor访问是状态

 

TypeCheckingVisitor.js:10  TypeCheckingVisitor VisitAssignment 
TypeCheckingVisitor.js:15  TypeCheckingVisitor VisitVariableRef 
CodeGeneratingVisitor.js:11  CodeGeneratingVisitor VisitAssignment 
CodeGeneratingVisitor.js:16  CodeGeneratingVisitor VisitVariableRef 

五、源代码下载

        下载链接:https://pan.baidu.com/s/1XuPqp84cccBNVkbnMY3sKw 
         提取码:q2ut

以上是关于JAVA SCRIPT设计模式--行为型--设计模式之Vistor访问者(23)的主要内容,如果未能解决你的问题,请参考以下文章

JAVA SCRIPT设计模式--行为型--设计模式之Strategy策略模式(21)

JAVA SCRIPT设计模式--行为型--设计模式之Iterator迭代器模式(16)

JAVA SCRIPT设计模式--行为型--设计模式之Responsibility职责链模式(13)

JAVA SCRIPT设计模式--行为型--设计模式之State状态者模式(20)

JAVA SCRIPT设计模式--行为型--设计模式之State状态者模式(20)

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