马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

观察者(Observer)模式——拉

  [复制链接]
查看6823 | 回复15 | 2021-3-6 21:41:56 | 显示全部楼层 |阅读模式
本帖最后由 剑弑 于 2021-3-6 21:47 编辑

       上一章我们有提到观察者模式具有推、拉两种实现,推的实现我们也在上一章讲了;哪么观察者模式拉的实现又是怎样的呢?在说之前我们先回顾下自媒体的哪个例子,作者每次上传视频平台都会第一时间通知推送给关注视频作者的粉丝用户,即使某些内容是用户不想要的也会推送,但这样的体验会很不好,我都不需要的东西你平台推送给我干嘛;这个时候用户就想了,要是能由我来确定拉取自己想要的内容就好了。
       不知道大家有没有去对比下两种观察者模式的例子,他们有什么的区别!!!
       推:由平台主动把视频去推送给用户,用户被动的接受;
       拉:由用户主动去平台拉取视频内容;
看完示例后,让我们傲娇的来看下代码的实现(毕竟我已经知道你大概是怎样的了),代码如下:
Subject
[C#] 纯文本查看 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Observer
{
    abstract class Subject
    {
        protected List<UserObserver> listObserver { get; set; } = new List<UserObserver>();

        protected bool chaned { get; set; }

        /// <summary>
        /// 注册观察者
        /// </summary>
        /// <param name="observer"></param>
        public void RegisterObserver(UserObserver observer)
        {
            listObserver.Add(observer);
        }

        /// <summary>
        /// 主题发布通知
        /// </summary>
        /// <param name="arg"></param>
        public void ReleaseObserver(object arg)
        {
            if (chaned)
            {
                foreach (var observer in listObserver)
                {
                    observer.Release(this, arg);
                }
            }
            chaned = false;
        }

        /// <summary>
        /// 主题发布通知
        /// </summary>
        public void ReleaseObserver()
        {
            ReleaseObserver(null);
        }

        /// <summary>
        /// 移除观察者
        /// </summary>
        /// <param name="observer"></param>
        public void RemoveObserver(UserObserver observer)
        {
            if (listObserver.IndexOf(observer) >= 0)
                listObserver.Remove(observer);
        }


    }
}

SelfMediaSubject
[C#] 纯文本查看 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Observer
{
    class SelfMediaSubject : Subject
    {
        #region 可整合成实体
        /// <summary>
        /// 视频内容
        /// </summary>
        private string byteContent;

        public string ByteContent
        {
            get { return byteContent; }
            set { byteContent = value; }
        }
        /// <summary>
        /// 视频发布时间
        /// </summary>
        public DateTime releaseDatetime;
        /// <summary>
        /// 视频名称
        /// </summary>
        public string name;
        #endregion

        /// <summary>
        /// 作者发布视频(拉)
        /// </summary>
        public void ReleaseVideo()
        {
            this.chaned = true;
            ReleaseObserver();
        }

        /// <summary>
        /// 主题数据更改
        /// </summary>
        /// <param name="byteContent"></param>
        /// <param name="releaseDatetime"></param>
        /// <param name="name"></param>
        public void setVideo(string byteContent, DateTime releaseDatetime, string name)
        {
            this.byteContent = byteContent;
            this.releaseDatetime = releaseDatetime;
            this.name = name;
            ReleaseVideo();
        }
    }
}

UserObserver
[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Observer
{
    interface UserObserver
    {
        void Release(Subject aSubject, object arg = null);
    } 
}

LiUserObserver
[AppleScript] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Observer
{
    class LiUserObserver : UserObserver
    {
        private Subject aSubject;

        #region 可整合成实体
        /// <summary>
        /// 视频内容
        /// </summary>
        private string byteContent;
        /// <summary>
        /// 视频发布时间
        /// </summary>
        private DateTime releaseDatetime;
        /// <summary>
        /// 视频名称
        /// </summary>
        private string name;
        #endregion

        public LiUserObserver(Subject subject)
        {
            aSubject = subject;
            aSubject.RegisterObserver(this);
        }

        public void Release(Subject aSubject, object arg = null)
        {
            SelfMediaSubject selfMedia = aSubject as SelfMediaSubject;
            this.byteContent = selfMedia.ByteContent;
            this.name = selfMedia.name;
            this.releaseDatetime = selfMedia.releaseDatetime;
            Console.WriteLine($"我是{typeof(LiuUserObserver).Name}");
            Console.WriteLine($"视频名称:{name},视频发布时间:{releaseDatetime}");
            Console.WriteLine("======================= 华丽分割线 =================================");
        }
    }
}

测试代码
[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Observer
{
    class Program
    {
        static void Main(string[] args)
        {
            SelfMediaSubject subject = new SelfMediaSubject();
            LiUserObserver liUserObserver = new LiUserObserver(subject);
            LiuUserObserver liuUserObserver = new LiuUserObserver(subject);
            LaiUserObserver laiUserObserver = new LaiUserObserver(subject);
            subject.setVideo("1111",DateTime.Now,"生活记录1");
            Console.WriteLine("移除liuUserObserver");
            subject.RemoveObserver(liuUserObserver);
            Console.WriteLine("****************** 华丽分割线 **********************");
            subject.setVideo("2222", DateTime.Now, "生活记录2");
            subject.setVideo("3333", DateTime.Now, "生活记录3");
            subject.setVideo("4444", DateTime.Now, "生活记录4");
            Console.ReadLine();
        }
    }
}

结果
2.png
类图
ClassDiagram1.png
       从上面的类图跟代码,我们可以看出Subject不在是接口,而是个抽象类;我们的注册、移除还有观察者集合都搬到了Subject,还多了个chaned的bool值(作用在此不做说明,聪明的你们一定一想就知);我们的发布通知也改成传参主题对象,我们的观察者们(LiUserObserver他们)获取数据也都变成了从主题类取值,达到了我们拉(要什么取什么)的需求。
      细心的朋友会发现多了个arg的参数是干嘛用的呢?代码里面也没用到啊!
      其实arg有很大的作用,比如当我们主题要传一些额外的数据时,我们就可以通过arg来传参,这样我们就不用去改动到Subject,无形中提高了我们模式的扩展性,当然你不要也行。
      还有朋友会问,我能不能推、拉两种都实现呢?这样我们用起来就更方便了!不是吗?
      对的!确实我们是可以推、拉一起实现,只要我们用上arg进行数据传递就成;只要给Subject增加多个设置数据方法,观察者接受收改一下设值就OK;注意别忘了设置chaned。
[C#] 纯文本查看 复制代码
/// <summary>
        /// 主题数据更改
        /// </summary>
        /// <param name="arg"></param>
        public void setVideo(object arg)
        {
            this.chaned = true;
            ReleaseObserver(arg);
        }
接下来我们来看看观察者模式的定义及优缺点
定义:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知并自动更新。
优点:
作者跟用户之间达到了松耦合,作者不用知道每一个用户啊什么,就可以把视频发送到用户手上。
缺点:
如果在作者(主题)跟用户(观察者)之间有循环依赖的话,作者(主题)会触发它们之间进行循环调用,导致系统崩溃。
至此我们的观察者模式就讲完了,有朋友可能会问,使用场景呢?有哪些?场景的话就留给大家去举一反三吧,毕竟说出来大家可能一会也就忘了,只有去思考了,举一反三了才能更深刻。

Observer - Pull.rar

91.16 KB, 阅读权限: 20, 下载次数: 0

ibcadmin | 2021-3-7 17:25:36 | 显示全部楼层
66666666666666
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
Amy尾巴 | 2021-3-8 08:59:08 | 显示全部楼层
6666666
剑弑 | 2021-3-9 14:29:49 | 显示全部楼层
剑弑 | 2021-3-9 14:30:06 | 显示全部楼层

666666666666666666
Empty风 | 2021-6-18 17:07:56 | 显示全部楼层
666666666666666666666666666666666
剑弑 | 2021-6-18 18:42:24 | 显示全部楼层
Empty风 发表于 2021-6-18 17:07
666666666666666666666666666666666

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则