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


        }
    }
相关推荐
ytttr8734 小时前
隐马尔可夫模型(HMM)MATLAB实现范例
开发语言·算法·matlab
天远Date Lab4 小时前
Python实战:对接天远数据手机号码归属地API,实现精准用户分群与本地化运营
大数据·开发语言·python
listhi5204 小时前
基于Gabor纹理特征与K-means聚类的图像分割(Matlab实现)
开发语言·matlab
qq_433776424 小时前
【无标题】
开发语言·php
Davina_yu5 小时前
Windows 下升级 R 语言至最新版
开发语言·windows·r语言
阿珊和她的猫5 小时前
IIFE:JavaScript 中的立即调用函数表达式
开发语言·javascript·状态模式
listhi5205 小时前
卷积码编码和维特比译码的MATLAB仿真程序
开发语言·matlab
yuan199975 小时前
基于主成分分析(PCA)的故障诊断MATLAB仿真
开发语言·matlab
J_liaty5 小时前
Java版本演进:从JDK 8到JDK 21的特性革命与对比分析
java·开发语言·jdk
翔云 OCR API6 小时前
发票查验接口详细接收参数说明-C#语言集成完整示例-API高效财税管理方案
开发语言·c#