观察者模式-猫叫了,老鼠跑了,主人醒了...

2024-01-30 12:59

本文主要是介绍观察者模式-猫叫了,老鼠跑了,主人醒了...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 现在很多程序员在面试的时候都遇到过这个问题---<猫叫了,老鼠跑了,主人醒了...>,实现一个连动效果,我也遇到过,感觉这道面试题目挺经典的,挺考验面向对象设计(OOD)的能力,虽然是个很简单的例子,但要考虑到程序的扩展性。比如说有新的需求,要求后面再加上狗叫了,那些写的过死且繁琐的代码就要来次大地震了;再比如说又变需求了,猫叫了是因为被跳蚤咬的,那跳蚤就成为了导火线,就算是用事件和接口写出的扩展性很强的程序,也会有点蔫了......

       这么一连串的反应是由一个行为所引起的,或者是猫叫,亦或者是一个按钮的点击引发,如何能让这一连串反映的扩展性更强,能更坚强的面对新的需求。这就需要一个更佳的思路,更佳的设计模式,今天无意想起了这个问题,也根据我的思路写了一套模式,下面就详细的说下我的想法:

       无论是猫叫,还是老鼠跑,都是一个行为,我们把这个行为抽象出一个基类:

    

 


 1 namespace NewCatAndMouse
 2 {
 3     public abstract class BaseObject
 4     {
 5         private string name;
 6 
 7         public string Name
 8         {
 9             get { return name; }
10             set { name = value; }
11         }
12 
13         /// <summary>
14         /// 抽象出的行为
15         /// </summary>
16         public abstract void Action();
17     }
18 }

 

      现在我们再建一个中间层,用来处理这些行为:

 

 


 1 namespace NewCatAndMouse
 2 {
 3     public class ActionHandle
 4     {
 5         private BaseObject manager;
 6 
 7         public ActionHandle(BaseObject manager,string name)
 8         {
 9             this.manager = manager;
10             this.manager.Name = name;
11         }
12 
13         /// <summary>
14         /// 执行
15         /// </summary>
16         public void Execute()
17         {
18             this.manager.Action();
19         }
20     }
21 }

 

       现在我们一一实现猫、老鼠和主人(从基类继承):

 

复制代码
 1 namespace NewCatAndMouse
 2 {
 3     public class Cat:BaseObject
 4     {
 5         public override void Action()
 6         {
 7             Console.Write(this.Name+"(猫)大吼一声!"+"\n");
 8         }
 9     }
10 }
复制代码

 

 

复制代码
 1 namespace NewCatAndMouse
 2 {
 3     public class Mouse:BaseObject
 4     {
 5         public override void Action()
 6         {
 7             Console.Write(this.Name+"(老鼠)仓惶逃跑!"+"\n");
 8         }
 9     }
10 }
复制代码

 

 

复制代码
 1 namespace NewCatAndMouse
 2 {
 3     public class Master:BaseObject
 4     {
 5         public override void Action()
 6         {
 7             Console.Write(this.Name+"(主人)猛然惊醒!" + "\n");
 8         }
 9     }
10 }
复制代码

 

      三个实现类完成了。现在一一实例化,组合调用?不,那样客户端会显的臃肿而丑陋,有人说:代码是门技术,更是门艺术。所以我们的客户端代码应当越简洁越好。所以,我们把需要的东西写在配置文件里:

 

 


 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <connectionStrings>
 4     <add name="AssemblyName" connectionString="NewCatAndMouse"/>
 5   </connectionStrings>
 6   <appSettings>
 7     <add key="Cat" value="Tom"/>
 8     <add key="Mouse" value="Jerry"/>
 9     <add key="Master" value="Bob"/>
10   </appSettings>
11 </configuration>

 

 

      然后我们再做一个类来处理配置文件:

 

 


 1 namespace NewCatAndMouse
 2 {
 3 
 4     public class SubjectAggregate
 5     {
 6         private static List<string> list = new List<string>();
 7         /// <summary>
 8         /// 将配置文件里的所有键读入集合,并返回
 9         /// </summary>
10         public static List<string> GetAllObject()
11         {
12             foreach(string key in ConfigurationManager.AppSettings.AllKeys)
13             {
14                 list.Add(key);
15             }
16 
17             if (list.Count < 1)
18             {
19                 return null;
20             }
21             else
22             {
23                 return list;
24             }
25         }
26         
27     }
28 }

 

       刚才说为了客户端的干净整洁,不要把过多的实例化放在客户端,所以我们就用反射来实例化类:

 


 1 namespace NewCatAndMouse
 2 {
 3     public class ReflectionObject
 4     {
 5 
 6         private static string assemblyName = System.Configuration.ConfigurationManager.ConnectionStrings["AssemblyName"].ConnectionString;
 7         
 8         /// <summary>
 9         /// 通过反射返回指定的类的实例
10         /// </summary>
11         /// <param name="key"></param>
12         /// <returns></returns>
13         public static BaseObject GetObject(string className)
14         {
15             return (BaseObject)Assembly.Load(assemblyName).CreateInstance(assemblyName+"."+className);
16         }
17     }
18 }

 

       下面就是客户端代码了:

 


 1 namespace NewCatAndMouse
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 8             List<string> list = SubjectAggregate.GetAllObject();
 9             if (list != null)
10             {
11                 for (int i = 0; i < list.Count; i++)
12                 {
13                     ActionHandle handle = new ActionHandle(ReflectionObject.GetObject(list[i]),System.Configuration.ConfigurationManager.AppSettings[list[i]].ToString());
14                     handle.Execute();
15                 }
16             }
17             else
18             {
19                 Console.Write("Not fount object!");
20             }
21 22             Console.Read();
23         }
24     }
25 }

 

         这样就可以了,如果需要新的子类直接继承基类,再在配置文件添加一个子类属性就可以了。而且可以再配置文件里自由的组合而无需改动客户端的代码,符合了开放--封闭原则。

         但由于用了反射,所以性能会有些差。而且如果实现类需要有新功能,就得在基类添加,如果功能太多基类就会变的臃肿不堪。所以,它也是有局限性的,最好是派生类不多而且行为较为统一。

         可能有人会说:那么简单的代码也好意思发上来。我想说:功能总能实现,就看怎样实现。这只是一个思路,由于更多的人把自己总结的不错的设计思路分享出来,所以我们才能进步。

         最近看设计模式有些上瘾,所以手痒也来凑凑热闹,但毕竟学程序的时间太短,经验太浅,所以可能有很多问题。希望大家帮我指正,希望能和大家一起努力,共同进步。

         附:让板砖来的更激烈些吧!

转载于:https://www.cnblogs.com/binyao/p/4898144.html

这篇关于观察者模式-猫叫了,老鼠跑了,主人醒了...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/660320

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易

使用Spring Boot集成Spring Data JPA和单例模式构建库存管理系统

引言 在企业级应用开发中,数据库操作是非常重要的一环。Spring Data JPA提供了一种简化的方式来进行数据库交互,它使得开发者无需编写复杂的JPA代码就可以完成常见的CRUD操作。此外,设计模式如单例模式可以帮助我们更好地管理和控制对象的创建过程,从而提高系统的性能和可维护性。本文将展示如何结合Spring Boot、Spring Data JPA以及单例模式来构建一个基本的库存管理系统