C# 23种设计模式(4)访问者模式(Visitor Pattern)

一、访问者模式介绍

**访问者模式(Visitor Pattern)**是一种行为设计模式,它允许你以一种新的方式来增加作用于一组对象的操作,而无需修改这些对象类的代码。访问者模式将数据操作与数据结构分离,适用于数据结构相对稳定但操作易于变化的情况。结构对象是使用访问者模式必备条件,而且这个结构对象必须存在遍历自身各个对象的方法。

优点:

  1. **扩展性好:**在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. **复用性好:**通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  3. **分离无关行为:**通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

访问者模式通常包含以下几个角色:

1、抽象访问者(Visitor)

为该对象结构中具体元素角色声明一个访问操作接口。

该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,

这样访问者就可以通过该元素角色的特定接口直接访问它:

2、具体访问者(Concrete Visitor)

实现Visitor声明的接口:

3、抽象元素(Element)

定义一个接受访问操作,它以一个访问者(Visitor)作为参数:

4、具体元素(Concrete Element)

实现了抽象元素所定义的接受操作接口:

5、对象结构(Object Structure)

可以提供一个高层接口以允许访问者访问它的元素。

二、工厂模式代码实现

假设使用场景

我们就以养宠物为例,宠物分别有狗和猫,要给宠物限食的话,主人可以吸,其他人也可以喂食。
访问者角色: 给宠物喂食的人
具体访问者角色: 主人、其他人
抽象元素角色: 动物抽象类
具体元素角色: 宠物狗、宠物猫
**结构对象角色:**主人家

场景代码实现如下:

cs 复制代码
    //抽象元素
    public interface IAnimal
    {
        void Accept(IPerson person);
    }
    //抽象访问者
    public interface IPerson
    {
        //优点定义对象结构的通用功能
        void Feed(Cat animal);
        void Feed(Dog animal);

        //缺点:一是依赖了具体类,违反了依赖倒置原则:二是每增加一个元素(宠物),这里就要增加一个方法,违反了开闭原则
    }
    //具体元素角色:猫
    public class Cat : IAnimal
    {
        public void Accept(IPerson person)
        {
            person.Feed(this);
            Console.WriteLine("猫:好吃");
        }
    }
    //具体元素角色:狗
    public class Dog : IAnimal
    {
        public void Accept(IPerson person)
        {
            person.Feed(this);
            Console.WriteLine("狗:好吃");
        }
    }
    //具体访问者:主人
    public class Master : IPerson
    {
        public void Feed(Cat animal)
        {
            Console.WriteLine("主人喂猫");
        }

        public void Feed(Dog animal)
        {
            Console.WriteLine("主人喂狗");
        }
    }
    //具体访问者:朋友
    public class Friend : IPerson
    {
        public void Feed(Cat animal)
        {
            Console.WriteLine("朋友喂猫");
        }

        public void Feed(Dog animal)
        {
            Console.WriteLine("朋友喂狗");
        }
    }
    //结构对象角色
    public class Home
    {
        private readonly List<IAnimal> animals = new List<IAnimal>();

        public void Add(IAnimal animal)
        {
            animals.Add(animal);
        }

        public void Start(IPerson person)
        {
            foreach (var animal in animals)
            {
                animal.Accept(person);
            }
        }
    }

    public class Client2
    {
        public static void Start()
        {
            Home home = new Home();
            home.Add(new Dog());
            home.Add(new Cat());

            Master master = new Master();
            home.Start(master);
            //输出:
            //主人喂狗
            //狗:好吃
            //主人喂猫
            //猫:好吃


        }
    }
相关推荐
CoderIsArt18 分钟前
C#中的CLR属性、依赖属性与附加属性
c#
风逸hhh1 小时前
python打卡day46@浙大疏锦行
开发语言·python
火兮明兮1 小时前
Python训练第四十三天
开发语言·python
季鸢1 小时前
Java设计模式之状态模式详解
java·设计模式·状态模式
ascarl20102 小时前
准确--k8s cgroup问题排查
java·开发语言
fpcc3 小时前
跟我学c++中级篇——理解类型推导和C++不同版本的支持
开发语言·c++
莱茵菜苗3 小时前
Python打卡训练营day46——2025.06.06
开发语言·python
爱学习的小道长3 小时前
Python 构建法律DeepSeek RAG
开发语言·python
luojiaao3 小时前
【Python工具开发】k3q_arxml 简单但是非常好用的arxml编辑器,可以称为arxml杀手包
开发语言·python·编辑器
终焉代码3 小时前
STL解析——list的使用
开发语言·c++