设计模式之行为型模式-访问者模式
作者:互联网
访问者模式(Visitor Pattern)
一、 介绍
模式定义:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
意图:主要将数据结构与数据操作分离。
主要解决:稳定的数据结构和易变的操作耦合问题。(被处理的数据元素相对稳定而访问方式多种多样)
何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
如何解决:在被访问的类里面加一个对外提供接待访问者的接口。
关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
应用实例:JDK 对于文件树的遍历(不变:文件树的遍历,变:文件的具体操作 如 打印文件名、计算文件数),ASM 修改字节码
优点: 1、符合单一职责原则。(访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。)
2、更强的扩展性。(能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。)
3、可维护性(复用性好)。(可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。)
4、灵活性。(访问者模式将数据结构与用作于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。)
缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素(被访问者的)变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。4、类结构变得复杂。(不是简单的调用关系,而是多个类之间的继承和组合关系)
使用场景: 1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。(不想直接被改变但又想扩展功能)
注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
二、详细
举例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
设计模式的本质是找出不变的东西,再找出变化的东西,然后找到合适的数据结构(设计模式)去承载这种变化。
访问者模式,重点在于访问二字,从字面上的意思理解:其实就相当于被访问者(如某个公众人物)把访问者(如 记者)当成了外人,不想你随便动。你想要什么,我弄好之后给你(调用你的方法)。访问者模式其实就是要把不变的东西固定起来,变化的开放出去。
三、结构
访问者(Visitor) 模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类,其主要角色如下:
- 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作visit(),该操作中的参数类型表示了被访问的具体元素。
- 具体访问者(Concrete Visitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
- 抽象元素(Element)角色:声明一个包含接受操作accept()操作,其方法体通常都是visitor.visit(this),另外具体元素中可能还包含业务本身逻辑的相关操作。
- 具体元素(Concrete Element)角色:实现抽象元素角色提供的accept()操作,其方法体通常都是visitor.visit(this),另外具体元素中可能还包含本身业务逻辑的相关操作。
- 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由List、Set、Map等聚合类实现。
结构图如下:
简单样例1(访问者类只有一个方法)
/**
* 抽象访问者
*/
interface Visitor{
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
/**
* 具体访问者A类
*/
class ConcreteVisitorA implements Visitor{
@Override
public void visit(ConcreteElementA element) {
System.out.println("具体访问者A访问->" + element.operationA());
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("具体访问者A访问->" + element.operationB());
}
}
/**
* 具体访问者B类
*/
class ConcreteVisitorB implements Visitor{
@Override
public void visit(ConcreteElementA element) {
System.out.println("具体访问者B访问->" + element.operationA());
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("具体访问者B访问->" + element.operationB());
}
}
/**
* 抽象元素类
*/
interface Element{
void accept(Visitor visitor);
}
/**
* 具体元素A类
*/
class ConcreteElementA implements Element{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationA(){
return "具体元素A的操作";
}
}
/**
* 具体元素B类
*/
class ConcreteElementB implements Element{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationB(){
return "具体元素B的操作";
}
}
/**
* 对象结构角色
*/
class ObjectStructure{
private List<Element> list = new ArrayList<Element>();//泛型
public void accept(Visitor visitor){
Iterator<Element> i = list.iterator();
while(i.hasNext()){
i.next().accept(visitor);
}
}
public void add(Element element){//增加
list.add(element);
}
public void remove(Element element){//删除
list.remove(element);
}
}
public class VisitorPatternSimpleTest {
public static void main(String[] args){
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.add(new ConcreteElementA());
objectStructure.add(new ConcreteElementB());
Visitor visitorA = new ConcreteVisitorA();
objectStructure.accept(visitorA);
System.out.println("------------------------------");
Visitor visitorB = new ConcreteVisitorB();
objectStructure.accept(visitorB);
}
}
执行:
三、案例
案例1:打印集合
PrintAggregate
public class PrintAggregate {
public static void main(String[] args) {
int[] x={2,3,4,5,10,9,8};
Collection collection = new ArrayList();
for(int i=0;i < x.length;i++){
collection.add(x[i]);
}
print(collection);
}
public static void print(Collection collection) {
Iterator it= collectlon.iterator ();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}
执行:
PrintAggregate2
public class PrintAggregate2 {
public static void main(String[] args) {
String[] a="Tianjin is one of the most beautiful city in China".aplit(" ");
/* Arrays.asList方法生成的1ist是List是使用的是类内部的构建ArrayList类,而不是我们常用的Java.util.ArrayList
它的内部类根本就没有写List的add方法,而是调用的java.util.AbstractList.add的add方法
而AbstractList的add方法会直接报出UnsupportedOperationException异常 */
Collection co = new ArrayList();
System.out.println(co.getClass());
Collection co2 = new ArrayList();
co2.add("1");
co2.add("2");
co.addAll(co2);
print(co);
}
public static void print(Collection collection) {
Iterator it= collectlon.iterator ();
while(it.hasNext()){
Object o=it.next();
if(o instanceof Collection){
print((Collection)o);
}else{
System.out.println(o.toString());
}
}
}
}
PrintAggregate3(强耦合,不推荐)
public class PrintAggregate2 {
public static void main(String[] args) {
String[] a="Tianjin is one of the most beautiful city in China".aplit(" ");
Collection co = new ArrayList();
Collection co2 = new ArrayList();
co2.add("1");
co2.add("2");
co2.add(3);
co2.add(4.0);
co2.add(5.6f);
co.addAll(co2);
print(co);
}
public static void print(Collection collection) {
Iterator it= collectlon.iterator ();
while(it.hasNext()){
Object o=it.next();
if(o instanceof Collection){
print((Collection)o);
}else if(o instanceof String){
System.out.println(" "+o.toString()+" ");
}else if(o instanceof Double){
System.out.println(o.toString()+"D");
}else if(o instanceof Float){
System.out.println(o.toString()+"f");
}else{
System.out.println(o.toString());
}
标签:void,元素,模式,element,add,设计模式,public,访问者 来源: https://www.cnblogs.com/oyww-2027/p/16289418.html