当前位置: 首页 > article >正文

二十、行为型(访问者模式)

访问者模式(Visitor Pattern)

概念
访问者模式是一种行为型设计模式,允许你在不修改被访问对象的前提下,定义新的操作。它通过将操作封装在访问者类中,从而将操作与对象结构分离。访问者模式非常适合于需要对一组对象进行不同操作的场景。


应用场景

  1. 对象结构稳定:当对象结构相对稳定,但需要为其添加新的操作时,访问者模式可以有效避免修改已有对象的代码。

  2. 复杂的对象结构:在复杂的对象结构中,可能需要对不同的对象执行不同的操作,访问者模式能够简化这些操作的实现。

  3. 需要对对象进行多次操作:当需要对对象进行多种不同操作时,可以使用访问者模式,将每种操作封装在不同的访问者中。

  4. 数据结构遍历:在某些数据结构(如树、图等)的遍历过程中,可以使用访问者模式来处理每个节点的操作。


注意点

  1. 增加新操作的灵活性:访问者模式允许灵活地增加新的操作,但添加新的元素(被访问对象)时,可能需要修改访问者接口,降低了扩展性。

  2. 对象结构的变化:如果对象结构经常变化,使用访问者模式可能会导致维护成本增加,因为每次变化都需要修改访问者的相关代码。

  3. 访问者与被访问者之间的耦合:访问者和被访问者之间的耦合性较强,可能影响到系统的可维护性。


核心要素

  1. Visitor(访问者接口):定义对每种具体元素的访问方法。

  2. ConcreteVisitor(具体访问者):实现访问者接口,定义具体的操作。

  3. Element(元素接口):定义接受访问者的接口。

  4. ConcreteElement(具体元素):实现元素接口,定义具体的被访问者。

  5. ObjectStructure(对象结构):维护一组元素,并提供对元素的遍历。


Java代码完整示例

示例:简单的访问者模式实现

// 访问者接口
interface Visitor {
    void visit(ConcreteElementA elementA);
    void visit(ConcreteElementB elementB);
}

// 具体访问者
class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElementA elementA) {
        System.out.println("Visiting ConcreteElementA");
    }

    @Override
    public void visit(ConcreteElementB elementB) {
        System.out.println("Visiting ConcreteElementB");
    }
}

// 元素接口
interface Element {
    void accept(Visitor visitor);
}

// 具体元素A
class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 具体元素B
class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 对象结构
class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

// 客户端代码
public class VisitorPatternDemo {
    public static void main(String[] args) {
        ObjectStructure structure = new ObjectStructure();
        structure.addElement(new ConcreteElementA());
        structure.addElement(new ConcreteElementB());

        ConcreteVisitor visitor = new ConcreteVisitor();
        structure.accept(visitor);
    }
}

输出结果

Visiting ConcreteElementA
Visiting ConcreteElementB

各种变形用法完整示例

  1. 多个具体访问者

    通过定义多个具体访问者来实现不同的操作。

    代码示例:多个访问者

    // 另一个具体访问者
    class AnotherVisitor implements Visitor {
        @Override
        public void visit(ConcreteElementA elementA) {
            System.out.println("AnotherVisitor visiting ConcreteElementA");
        }
    
        @Override
        public void visit(ConcreteElementB elementB) {
            System.out.println("AnotherVisitor visiting ConcreteElementB");
        }
    }
    
    public class MultiVisitorDemo {
        public static void main(String[] args) {
            ObjectStructure structure = new ObjectStructure();
            structure.addElement(new ConcreteElementA());
            structure.addElement(new ConcreteElementB());
    
            ConcreteVisitor visitor1 = new ConcreteVisitor();
            structure.accept(visitor1); // 使用第一个访问者
    
            AnotherVisitor visitor2 = new AnotherVisitor();
            structure.accept(visitor2); // 使用第二个访问者
        }
    }
    
  2. 访问者的复杂操作

    访问者可以执行更复杂的操作,比如在访问时修改元素的状态。

    代码示例:复杂操作

    // 具体元素A
    class ConcreteElementA implements Element {
        private int value;
    
        public ConcreteElementA(int value) {
            this.value = value;
        }
    
        public int getValue() {
            return value;
        }
    
        public void setValue(int value) {
            this.value = value;
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }
    
    // 具体访问者:增加值
    class IncrementVisitor implements Visitor {
        @Override
        public void visit(ConcreteElementA elementA) {
            int newValue = elementA.getValue() + 1;
            elementA.setValue(newValue);
            System.out.println("Incremented ConcreteElementA value to: " + newValue);
        }
    
        @Override
        public void visit(ConcreteElementB elementB) {
            // 不做任何操作
        }
    }
    
    public class IncrementVisitorDemo {
        public static void main(String[] args) {
            ObjectStructure structure = new ObjectStructure();
            ConcreteElementA elementA = new ConcreteElementA(10);
            structure.addElement(elementA);
            structure.addElement(new ConcreteElementB());
    
            IncrementVisitor incrementVisitor = new IncrementVisitor();
            structure.accept(incrementVisitor); // 增加元素A的值
        }
    }
    
  3. 遍历复杂对象结构

    对于树形结构等复杂对象,可以使用访问者模式进行遍历和操作。

    代码示例:树形结构

    // 树形元素接口
    interface TreeElement extends Element {
        List<TreeElement> getChildren();
    }
    
    // 具体树形元素
    class TreeNode implements TreeElement {
        private String name;
        private List<TreeElement> children = new ArrayList<>();
    
        public TreeNode(String name) {
            this.name = name;
        }
    
        public void addChild(TreeElement child) {
            children.add(child);
        }
    
        @Override
        public List<TreeElement> getChildren() {
            return children;
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
            for (TreeElement child : children) {
                child.accept(visitor);
            }
        }
    
        public String getName() {
            return name;
        }
    }
    
    // 具体访问者:打印节点名称
    class PrintVisitor implements Visitor {
        @Override
        public void visit(ConcreteElementA elementA) {
            // 不做任何操作
        }
    
        @Override
        public void visit(ConcreteElementB elementB) {
            // 不做任何操作
        }
    
        @Override
        public void visit(TreeNode treeNode) {
            System.out.println("Visiting TreeNode: " + treeNode.getName());
        }
    }
    
    public class TreeStructureDemo {
        public static void main(String[] args) {
            TreeNode root = new TreeNode("Root");
            TreeNode child1 = new TreeNode("Child 1");
            TreeNode child2 = new TreeNode("Child 2");
    
            root.addChild(child1);
            root.addChild(child2);
            child1.addChild(new TreeNode("Child 1.1"));
    
            PrintVisitor printVisitor = new PrintVisitor();
            root.accept(printVisitor); // 遍历树结构
        }
    }
    

通过这些示例,访问者模式的灵活性和应用场景得以体现,可以根据具体需求实现多种变形用法。


http://www.kler.cn/news/367972.html

相关文章:

  • PortQry下载安装使用教程(超详细),Windows测试UDP端口
  • 来源爬虫程序调研报告
  • Java中的设计模式:单例模式详解
  • JAVA篇之类和对象
  • Vue3 学习笔记(五)Vue3 模板语法详解
  • R语言机器学习算法实战系列(十四): CatBoost分类算法+SHAP值 (categorical data gradient boosting)
  • Java学习Day53:铲除紫云山金丹原料厂厂长(手机快速登录、权限控制)
  • 浅谈AI大模型的数据特点和应用问题
  • JavaEE初阶---多线程(五)---定时器/线程池介绍
  • 如何在国内安装使用Python,国内镜像站点加速库的安装
  • 用哪种建站程序做谷歌SEO更容易?
  • P6458 [COCI2006-2007#5] LIGA
  • 算法汇总整理篇——贪心与动态规划学习及框架思考
  • ReactNative 启动应用(2)
  • 【Linux操作系统】Linux配置OpenSSH服务器步骤记录
  • 【Linux】操作系统初步理解与Linux指令入门
  • CesiumJS 案例 P6:添加图片图层、添加图片图层并覆盖指定区域
  • Kafka文档阅读笔记之基本操作
  • js构造函数和原型对象,ES6中的class,四种继承方式
  • FreeSWITCH 简单图形化界面30 - 使用MYODBC时可能遇到的错误
  • 宝塔-修改docker加速镜像-daemon.json配置文件格式错误!
  • android 与网页交互通过网页修改宿主布局和异常处理——未来之窗行业应用跨平台架构
  • 【OpenAI】第五节(图像生成)利用 OpenAI 的 DALL·E 实现自动化图像生成:从文本到图像的完整教程
  • 【报错解决】C++ 出现错误error: default argument given for parameter的解决办法
  • 15分钟学 Go 第 14 天:切片
  • 详细解读 CVPR2024:VideoBooth: Diffusion-based Video Generation with Image Prompts