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


        }
    }
相关推荐
ShiXZ21315 分钟前
Java 8 Stream API 实用技巧详解:从入门到精通
java·开发语言
冻柠檬飞冰走茶23 分钟前
PTA基础编程题目集 7-27 冒泡法排序(C语言实现)
c语言·开发语言·数据结构·算法
听雨入夜31 分钟前
“同声传译”还是“全文翻译”?为何HotSpot虚拟机仍要保留解释器?
开发语言·python
随风M记忆s35 分钟前
GEE&Python-demo:利用Sentinel-监测北京奥林匹克森林公园年NDVI变化(附Python版)
开发语言·python·sentinel
C++、Java和Python的菜鸟1 小时前
第9章 后端Web进阶(AOP)
java·开发语言·前端
软萌萌的11 小时前
Python零基础从入门到精通详细教程-数据类型
开发语言·windows·python
姓蔡小朋友1 小时前
Java线程并发
java·开发语言·python
我星期八休息1 小时前
扩展— TCP 全连接队列与 tcpdump 抓包
linux·服务器·开发语言·前端·网络·tcp/ip·tcpdump
SunnyDays10112 小时前
C# 加密和解密 PDF:设置密码、AES 加密及操作权限
pdf·c#·加密 pdf·解除 pdf 密码·pdf 权限设置·pdf 文档安全
小小代码狗2 小时前
PHP 常用函数与变量参考文档
开发语言·安全·php