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);
            //输出:
            //主人喂狗
            //狗:好吃
            //主人喂猫
            //猫:好吃


        }
    }
相关推荐
李少兄1 分钟前
Java 基本数据类型 vs 包装类(引用数据类型)
java·开发语言·python
拓端研究室TRL8 分钟前
Python贝叶斯分层模型专题|对环境健康、医学心梗患者、体育赛事数据空间异质性实证分析合集|附数据代码
开发语言·python
chxii4 小时前
5.go切片和map
开发语言·golang
技术干货贩卖机6 小时前
MATLAB绘图配色包说明
开发语言·matlab
胡耀超6 小时前
7.模型选择与评估:构建科学的参数调优与性能评估体系——Python数据挖掘代码实践
开发语言·人工智能·python·机器学习·数据挖掘
沐墨专攻技术6 小时前
深入理解指针(4)(C语言版)
c语言·开发语言
南屿欣风6 小时前
Go 语言中使用 Swagger 生成 API 文档及常见问题解决
开发语言·后端·golang
Faxxtty7 小时前
【R语言】无法调用stats.dll的问题解决方案
开发语言·r语言
hhcyyds17 小时前
【C#】变量和常量
c#
alden_ygq7 小时前
Go 语言常见错误——控制结构
开发语言·后端·golang