行为型模式 - 访问者模式Visitor
学习而来,代码是自己敲的。也有些自己的理解在里边,有问题希望大家指出。
行为型模式,我之所以把他放到第一个,是因为它号称是GoF中最难的一个。

模式的定义与特点
在访问者模式中(Visitor Pattern)中,我们使用了一个访问者类,他改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。根据访问者模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
模式的优点
- 符合单一职责原则。
- 拥有优秀的扩展性。
- 非常灵活。
模式的缺点
- 具体元素对访问者公布细节,违反了迪米特法则。
- 具体元素变更比较困难。
- 依赖了具体类,没有依赖抽象,这违反了依赖倒置原则。

举例使用场景
说在某个厨师交流会上,有三个人一拍即合要开餐馆。这三个人分别是一个老板、一个中国厨师、一个西方厨师。餐馆开起来后客人络绎不绝,但两位厨师用的没油了,提出要加服务员跑腿。老板不同意啊,多一个人就得多开钱啊,于是让两位厨师自行解决。并且说不管是这次的油,还是之后还有别的需求都让两个厨师自己解决。
分析故事:永远只有三个人,所有事情都需要两个厨师自己解决。
想到的解决办法:
- 更改厨师类,新增获取油或者是其他需求时,进行类的扩展,这样不符合开闭原则
- 抽象厨师类,每次有新的需求时新增一个厨师就行,这样看似符合开闭原则,且解决了问题,但题目内容本身,是不允许新增员工的。
- 被制作的东西告诉厨师:"1、你需要做我。2、我是你怎么做出来的 ",然后厨师做出了这个东西。这样之后厨师需要做什么,原有代码都不需要修改,只需要增加被生产的内容类即可。这样符合开闭原则,也完美的解决了问题。
根据题目与结论得出,应该有俩厨师类,一个被生产类。
俩厨师类来做东西(访问者),通过访问者:“1:告知厨师类需求做出自己,2:告知厨师类怎么制作自己”。
internal class Program {
static void Main(string[] args) {
List<Cooker> cookers = new List<Cooker>() { //获取所有厨师
new ChineseChef(),
new WesternChef(),
};
Visitor meat = new MeatVisitor(); //获取肉类访问者
Visitor oil = new GetOilVisitor(); //获取油类访问者
for (int i = cookers.Count - 1; i >= 0; i--) {
//cookers[i].Cooking(meat); //告诉厨师需要做什么内容(肉)
cookers[i].Cooking(oil); //告诉厨师需要做什么内容(油)
}
Console.ReadLine();
}
}
//===================================================================================================
internal abstract class Cooker { //厨师抽象类
public string Name; //厨师
public abstract void Cooking(Visitor visitors); //抽象出做东西 参数:做的内容(访问者)
}
internal class ChineseChef : Cooker {
public override void Cooking(Visitor visitors) {
Name = "中国厨师";
visitors.Chinesechef(this); //告诉访问者,现在是中国厨师在做
}
}
internal class WesternChef : Cooker {
public override void Cooking(Visitor visitors){
Name = "西方厨师";
visitors.Westernchef(this); //告诉访问者,现在是西方厨师在做
}
}
//===================================================================================================
internal abstract class Visitor { //访问者类抽象
public abstract void Chinesechef(Cooker cookers); //抽象出 中国厨师怎么做自己
public abstract void Westernchef(Cooker cookers); //抽象出 西方厨师怎么做自己
}
internal class MeatVisitor : Visitor { //定义访问者自身为肉
public override void Chinesechef(Cooker cookers) { //告诉中国厨师自己怎么做
Console.WriteLine($"{cookers.Name}认为,肉 要煮的吃");
//Console.WriteLine("中国厨师认为,肉 要煮的吃");
}
public override void Westernchef(Cooker cookers) { //告诉西方厨师自己怎么做
Console.WriteLine($"{cookers.Name}认为,肉 要煎的吃");
//Console.WriteLine("西方厨师认为,肉 要煎的吃");
}
}
internal class GetOilVisitor : Visitor {
public override void Chinesechef(Cooker cookers) {
Console.WriteLine($"{cookers.Name}认为,油 可以通过肉炼出来");
//Console.WriteLine("中国厨师认为,油 可以通过肉炼出来");
}
public override void Westernchef(Cooker cookers) {
Console.WriteLine($"{cookers.Name}认为,油 应该去超市买");
//Console.WriteLine("西方厨师认为,油 应该去超市买");
}
}

希望大家:点赞,留言,关注咯~
唠家常
今日分享结束啦,小伙伴们你们get到了么,你们有没有更好的办法呢,可以评论区留言分享,也可以加我QQ:841298494,大家一起进步。
- 客官,看完get之后记得点赞哟!
- 小伙伴你还想要别的知识?好的呀,分享给你们
今日推荐
行为型模式 - 访问者模式Visitor的更多相关文章
- 【设计模式】行为型09访问者模式(Visitor Pattern)
学习地址:https://blog.csdn.net/u012124438/article/details/70537203(参考了很多博客,只有这个讲明白了核心点) 访问者模式(Visitor P ...
- 【GOF23设计模式】解释器模式 & 访问者模式
来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_解释器模式.访问者模式.数学表达式动态解析库式 1.解释器模式Interpreter 2.访问者模式Visitor
- 访问者(Visitor)模式
http://www.cnblogs.com/zhenyulu/articles/79719.html 一. 访问者(Visitor)模式 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作. ...
- C#设计模式——访问者模式(Visitor Pattern)
一.概述由于需求的改变,某些类常常需要增加新的功能,但由于种种原因这些类层次必须保持稳定,不允许开发人员随意修改.对此,访问者模式可以在不更改类层次结构的前提下透明的为各个类动态添加新的功能.二.访问 ...
- B7:访问者模式 Visitor
表示一个作用于某对象结构中各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 适用场景:1.适用于元素类数据结构相对稳定(类的方法固定,但属性可以变化,如果方法变化很大,就无 ...
- 浅谈设计模式-visitor访问者模式
先看一个和visitor无关的案例.假设你现在有一个书架,这个书架有两种操作,1添加书籍2阅读每一本书籍的简介. //书架public class Bookcase { List<Book> ...
- 折腾Java设计模式之访问者模式
博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...
- C#设计模式学习笔记:(21)访问者模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8135083.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第九个模式--访 ...
- [Python设计模式] 第28章 男人和女人——访问者模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 用程序模拟以下不同情况: 男人成功时,背后多半有一个伟大的女人: 女人成功 ...
随机推荐
- python学习——查找计算机中的文件
# import os # # path = 'C:/Users/admin/Desktop/images' # files = os.listdir(path) # # for f in files ...
- SpringBoot yml配置文件中,logging.level报错
报错 *************************** APPLICATION FAILED TO START *************************** Description: ...
- HTTPS详解二
前言 在上篇文章中,我已经为大家介绍了 HTTPS 的详细原理和通信流程,但总感觉少了点什么,应该是少了对安全层的针对性介绍,那么这篇文章就算是对HTTPS 详解一的补充吧.还记得这张图吧. HTTP ...
- (工具) 交叉编译 gperftools及使用
交叉编译gperftools及使用 sudo apt-get install kcachegrind # 导出为 callgrind 格式时需要 sudo apt install doxygen-la ...
- WebApi实现Token验证
为什么要实现Token呢.在我们客户端发送请求时,如果没有校验数据是否合法那么就有可能造成非法请求泄露我们的数据 实现Token的思路 1.客户端通过用户名和密码来获取Token 通过自己的账号和密码 ...
- 如何实现一个优秀的 HashTable 散列表?
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 前言 大家好,我是小彭. 在前几篇文章里,我们聊到了 Java 中的几种线性表结构,包括 ArrayList ...
- 记录一次PyQt5内存泄漏的问题解决
前言 前几天利用python-mpv写了一个播放器,但是跑着跑着发现内存越来越大,经过我反复调试终于解决了这个问题. 解决思路 模块定位 首先我是一个模块一个模块测试的,这样可以尽快缩减出问题的代码范 ...
- 【每日一题】【模拟】2021年11月11日--LRU 缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 .实现 LRUCache 类: LRUCache(int capacity) 以正整数作为容量 capacity 初始化 L ...
- TS编写发布订阅模式
interface PubSubType { events: { [key: string]: { name: string, once: boolean, cb: Function }[] } on ...
- eval解析的函数传参 object array
1 const fn = (...args) => { 2 console.log(...args) 3 } 4 5 const handleEval = (fnName,...args) =& ...