『观察者模式』来钓鱼

作者: 圣杰 | 来源:发表于2017-01-25 16:41 被阅读691次

目录:设计模式之小试牛刀
源码路径:Github-Design Pattern


一人多竿来钓鱼

定义:(Observer Pattern)

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

类图:

观察者模式通用类图

启示:

最近工作好不繁忙,累的是腰酸脖子疼,这不周末了决定忙里偷闲,去公园散散步,换换心情。
逃离了键盘鼠标,整个世界都清净了。
漫步在公园小径,吹着小风晒着太阳补着钙,好不自在。
走到池塘边,一阵铃铛声吸引了我的注意力。定睛一看,原来是鱼儿咬钩了。只见垂钓者赶紧从旁边的草坪上跑过来收杆拉线,好家伙,钓了个够猫尝个腥塞个牙缝的鱼儿。取下鱼,重新放上鱼饵,把钩一摔,垂钓者就撒手去旁边草坪和朋友打牌去了。和旁边其他一心垂钓的钓客相比,这货明显是更会享受啊,即钓了鱼又晒了太阳打了牌,简直开了多线程啊。

我这人就爱灵光一闪,这不就是观察者模式吗?!

鱼竿,铃铛,垂钓者。
鱼竿是被观察者,
铃铛是通知工具,
垂钓者是观察者。

鱼儿咬钩,鱼竿通过铃铛通知垂钓者收钩。

多么经典的观察者模式生活实例啊。

这灵光一闪,可是要立马记录啊。打开手机滴答清单记下【应用观察者模式实现钓鱼示例】。

回到家,打开电脑,一会噼里啪啦,就完成了以下观察者模式示例。

代码:(简单实现)

先来定义鱼的品类枚举:

public enum FishType
{
    鲫鱼,
    鲤鱼,
    黑鱼,
    青鱼,
    草鱼,
    鲈鱼
}

接下来申明一个钓鱼工具的抽象类,维护订阅者列表,并负责循环通知订阅者。

  /// <summary>
 ///     钓鱼工具抽象类
 ///     用来维护订阅者列表,并通知订阅者
 /// </summary>
 public abstract class FishingTool
 {
     private readonly List<ISubscriber> _subscribers;

     protected FishingTool()
     {
         _subscribers = new List<ISubscriber>();
     }

     public void AddSubscriber(ISubscriber subscriber)
     {
         if (!_subscribers.Contains(subscriber))
             _subscribers.Add(subscriber);
     }

     public void RemoveSubscriber(ISubscriber subscriber)
     {
         if (_subscribers.Contains(subscriber))
             _subscribers.Remove(subscriber);
     }

     public void Notify(FishType type)
     {
         foreach (var subscriber in _subscribers)
             subscriber.Update(type);
     }
 }

鱼竿的实现,这里用随机数模拟鱼儿咬钩:

 /// <summary>
///     鱼竿
/// </summary>
public class FishingRod : FishingTool
{
    public void Fishing()
    {
        Console.WriteLine("开始下钩!");

        //用随机数模拟鱼咬钩,若随机数为偶数,则为鱼咬钩
        if (new Random().Next() % 2 == 0)
        {
            var type = (FishType) new Random().Next(0, 5);
            Console.WriteLine("铃铛:叮叮叮,鱼儿咬钩了");
            Notify(type);
        }
    }
}

定义简单的观察者接口:

/// <summary>
///     订阅者(观察者)接口
///     由具体的订阅者实现Update()方法
/// </summary>
public interface ISubscriber
{
    void Update(FishType type);
}

垂钓者实现观察者接口,并定义了Name,FishCount属性:

/// <summary>
///     垂钓者实现观察者接口
/// </summary>
public class FishingMan : ISubscriber
{
    public FishingMan(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
    public int FishCount { get; set; }

    public void Update(FishType type)
    {
        FishCount++;
        Console.WriteLine("{0}:钓到一条[{2}],已经钓到{1}条鱼了!", Name, FishCount, type);
    }
}

来看看场景类:

 /// <summary>
 ///     测试简单实现的观察者模式
 /// </summary>
 private static void SimpleObserverTest()
 {
     Console.WriteLine("简单实现的观察者模式:");
     Console.WriteLine("=======================");
     //1、初始化鱼竿
     var fishingRod = new FishingRod();

     //2、声明垂钓者
     var jeff = new FishingMan("圣杰");

     //3、将垂钓者观察鱼竿
     fishingRod.AddSubscriber(jeff);

     //4、循环钓鱼
     while (jeff.FishCount < 5)
     {
         fishingRod.Fishing();
         Console.WriteLine("-------------------");
         //睡眠5s
         Thread.Sleep(5000);
     }
 }
简单实现测试结果

以上就是观察者模式的简单实现,通过此例,是不是发现观察者模式也不过如此。

代码:(委托实现)

.Net中有一个好东西,就是委托,对它不了解的可以看看这篇博文C# 中的委托和事件

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

那委托在观察者模式中如何应用呢,让我们来以且听我娓娓道来:

有了委托,我们就不再需要定义专门的抽象被观察者对象了,直接实现鱼竿:

 /// <summary>
 ///     鱼竿
 /// </summary>
 public class FishingRod
 {
     public delegate void FishingHandler(FishType type); //声明委托
     public event FishingHandler FishingEvent; //声明事件

     public void Fishing()
     {
         Console.WriteLine("开始下钩!");

         //用随机数模拟鱼咬钩,若随机数为偶数,则为鱼咬钩
         if (new Random().Next() % 2 == 0)
         {
             var a = new Random(10).Next();
             var type = (FishType) new Random().Next(0, 5);
             Console.WriteLine("铃铛:叮叮叮,鱼儿咬钩了");
             if (FishingEvent != null)
                 FishingEvent(type);
         }
     }
 }

因为被观察者定义了委托,我们也没必要定义专门的观察者接口,只需要在具体的观察者中实现对应的委托即可。

/// <summary>
///     垂钓者(观察者)
/// </summary>
public class FishingMan
{
    public FishingMan(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
    public int FishCount { get; set; }

    public void Update(FishType type)
    {
        FishCount++;
        Console.WriteLine("{0}:钓到一条[{2}],已经钓到{1}条鱼了!", Name, FishCount, type);
    }
}

看看场景类:

/// <summary>
///     测试委托实现的观察者模式
/// </summary>
private static void DelegateObserverTest()
{
    Console.WriteLine("委托实现的观察者模式:");
    Console.WriteLine("=======================");
    //1、初始化鱼竿
    var fishingRod = new DelegateImplement.FishingRod();

    //2、声明垂钓者
    var jeff = new DelegateImplement.FishingMan("圣杰");

    //3、注册观察者
    fishingRod.FishingEvent += jeff.Update;

    //4、循环钓鱼
    while (jeff.FishCount < 5)
    {
        fishingRod.Fishing();
        Console.WriteLine("-------------------");
        //睡眠5s
        Thread.Sleep(5000);
    }
}
委托实现观察者模式测试结果

总结:

观察者模式中有两个关键字,通知和更新。
被观察者状态改变通知观察者做出相应更新。
解决的是当对象改变时需要通知其他对象做出相应改变的问题。

优缺点:

优点
观察者和被观察者之间是抽象耦合,易于扩展;
可构造一套触发机制,形成广播链,支持广播通信;
缺点
若一个对象存在较多的观察者,则通知观察者存在效率问题;
观察者和被观察者间可能会导致循环依赖,导致系统奔溃。

应用场景:

  • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
  • 事件多级触发场景。
  • 跨系统的消息交换场景,如消息队列的处理机制。

相关文章

  • 『观察者模式』来钓鱼

    目录:设计模式之小试牛刀源码路径:Github-Design Pattern 定义:(Observer Patte...

  • 设计模式之观察者模式

    观察者模式 Rxjava中运用到了观察者模式,那什么是观察者模式呢,现在来学习一下。正所谓观察,就是看,细察事物的...

  • 【设计模式】---观察者模式与发布订阅者模式

    一、观察者模式和发布订阅者模式之间的区别 观察者模式中观察者和目标直接进行交互, 而发布订阅模式由统一的调度中心来...

  • 11.9设计模式-观察者模式-详解

    设计模式-观察者模式 观察者模式详解 观察者模式在android中的实际运用 1.观察者模式详解 2.观察者模式在...

  • 简单设计模式——观察者模式

    设计模式其实不难,难得是根据实际情况使用合适的设计模式来实现业务逻辑。 观察者模式简介 观察者模式(Observe...

  • RxJava基础—观察者模式

    设计模式-观察者模式 观察者模式:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式...

  • 观察者模式

    What 观察者模式 我们可以先通过生活上的事情来认识观察者模式,在日常生活中订阅报纸就可以看成是观察者模式的实现...

  • 前端面试考点之手写系列

    1、观察者模式 观察者模式(基于发布订阅模式) 有观察者,也有被观察者。 观察者需要放到被观察者列表中,被观察者的...

  • NSNotificationCenter实现原理

    NSNotificationCenter是使用观察者模式来实现的用于跨层传递消息。 观察者模式 定义对象间的一种一...

  • RxJava 原理篇

    一、框架思想 观察者模式观察者自下而上注入被观察者被观察者自上而下发射事件观察者模式 装饰器模式自上而下,被观察者...

网友评论

  • 叮宕:竟然没评论……
    观察者模式在行为模式中确实常用,多数什么按键事件绑定用的都是这个。个人感觉,模式学到最后就是对面向对象五大原则的再理解了。
    圣杰: @叮宕 总结的不错,看来对设计模式的运用比较娴熟。以后有相关的问题就向你请教😀
    叮宕:@圣杰 我接触的,java 安卓感觉用的比较多。比如java各种各样的流就是装饰模式,集合都实现了迭代器模式,简单工厂到处都是,安卓中就更多了,它的各种组件都是面向对象原理的体现,比如更新的api也能体现出,越来越解耦合,是谁的责任就交给谁。
    web方面各个框架大体都是实现了前端控制器模式,和我称之为粒度化的MVC模式。前者是对路由的解决,后者是对分离的需要。
    像是python,linux shell确实对于模式用的少。我觉得是想java考虑的是健壮有序,而脚本锋利就好,一个sharp的脚本就够了。像是linux shell,它强调的是合作,一个的结果作为一个的输入,简单有用单一。
    圣杰: @叮宕 嗯,是的。我现在只是将设计模式简单过一遍,有个基本认知。也许只有到真正实践到项目中去,才会有更深的认识。

本文标题:『观察者模式』来钓鱼

本文链接:https://www.haomeiwen.com/subject/dcribttx.html