zoukankan      html  css  js  c++  java
  • 观察者模式

    摘要

    本文以C#示例说明观察者模式的概念和应用场景。

    定义

    观察者模式(Observer Pattern <[əb'zɝvɚ] ['pætɚn]>, 有时又被称为发布&订阅(Publish&Subscribe)模式)是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。维基百科

    Alt Text

    解读

    • 关键词:发布-订阅
    • 应用场景:猎头招聘,日志系统,新用户注册
    • 被观察者知道观察者的存在,并能调用观察者提供的接口,比如求职者和猎头之间的关系;
    • 目的:解决观察者和信息发布者之间的耦合问题。

    现实生活中的场景

    • 微信朋友圈
    • ...

    下面用代码示例进行说明:

    Alt Text

    场景

    日志消息的记录和打印,产生的字符串类型的日志消息分别在控制台/屏幕打印和记录文本/磁盘文件。

    具体实现如下

    using System;
    using System.IO;
    
    public interface ILogObserver
    {
        int id { get; set; }
        void Insert(string message);
    }
    
    public class LogSubject
    {
        // 观察者队列
        private List<ILogObserver> observers;
    
        public LogSubject()
        {
            observers = new List<ILogObserver>();    
        }
    
        // 观察者注册
        public void Register(ILogObserver obs)
        {
            if (!observers.Exists(ob=>ob.id==obs.id)
            {
                observers.add(obs); 
            }
        }
    
        // 观察者移除
        public void Remove(ILogObserver obs)
        {
            if (observers.Exists(ob=>ob.id==obs.id)
            {
                observers.Remove(obs); 
            }
        }
    
        // 调用观察者接口
        public void Notify(string message)
        {
            foreach (ILogObserver obs in observers)
            {
                obs.Insert(message);
            }
        }
    }
    
    /// <summary>控制台日志</summary>
    public class ConsoleLog: ILogObserver
    {
    
        public int id { get; set; }    
    
        public void Insert(string message)
        {
            System.Console.WriteLine(message);
        }
    }
    
    /// <summary>文本日志</summary>
    public class TextLog: ILogObserver
    {
        public int id { get; set; }    
    
        public void Insert(string message)
        {
            string filePath = "x:\log.txt";
            System.File.AppendLine(filePath, message);
        }
    }
    
    
    

    使用事件实现

    在 .Net 中,可以利用事件和委托简化观察者模式的实现,上面的例子可以修改如下:

    
        // 定义委托
        public delegate void LogInsertedEventHandler<LogInsertEventArgs>(string message);
    
        // 被观察者
        public class LogInserter
        {
            public LogInsertedEventHandler<LogInsertEventArgs>  LogInserted;
    
            public void AddObserver(LogInsertedEventHandler<LogInsertEventArgs> handler)
            {
                LogInserted += handler;
            }
    
            public void RemoveObserver(LogInsertedEventHandler<LogInsertEventArgs> handler)
            {
                LogInserted -= handler;
            }
    
            public void Insert(string message) => LogInserted?.Invoke(message);
        }
    
        // 委托/事件参数
        public class LogInsertEventArgs : EventArgs
        {
            public string Message { get; set; }
    
            public LogInsertEventArgs(string message)
            {
                this.Message = message;
            }
        }
    
        // 订阅者接口
        public interface ILogSubscriber
        {
            void LogInserted(string message);
        }
    
        // 订阅者实现(控制台打印)
        public class ConsoleLogSubscriber : ILogSubscriber
        {
            public void LogInserted(string message)
            {
                Console.WriteLine($"日志打印到屏幕: {message}");
            }
        }
    
        // 订阅者实现(追加到文本)
        public class TextLogSubscriber : ILogSubscriber
        {
            public void LogInserted(string message)
            {
                Console.WriteLine($"日志追加到文本: {message}");
            }
        }
    
        // 调用
    
        class Program
        {
            static void Main(string[] args)
            {
                // 被观察者
                LogInserter ins = new LogInserter();
    
                // 观察者定义
                TextLogSubscriber textSub = new TextLogSubscriber();
                ConsoleLogSubscriber consoleSub = new ConsoleLogSubscriber();
    
                // 添加观察者
                ins.AddObserver(handler: new LogInsertedEventHandler<LogInsertEventArgs>(textSub.LogInserted));
                ins.AddObserver(handler: new LogInsertedEventHandler<LogInsertEventArgs>(consoleSub.LogInserted));
    
                // 产生日志
                ins.Insert("这是日志内容");
    
                Console.ReadLine();
            }
        }
    
    

    输出如下:

    日志追加到文本: 这是日志内容
    日志打印到屏幕: 这是日志内容
    

    All Text

    好了,今天的观察者模式就总结到这里,大家继续回去写BUG吧

  • 相关阅读:
    什么是API
    Maxiee的Vim入门日记(4)——安装windows下的Cscope
    将字符串变成大写----C++实现
    POJ 3254 炮兵阵地(状态压缩DP)
    UIKit和Core Graphics绘图(三)——绘制虚线,椭圆以及饼图
    CRC 模式及实现
    [HDU 1317]XYZZY[SPFA变形][最长路]
    poj 2155 Matrix
    [置顶] Application,Session,Cookie之Application对象
    [Todo] Java及C++ Exception整理
  • 原文地址:https://www.cnblogs.com/zanpen2000/p/7566803.html
Copyright © 2011-2022 走看看