意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

设计模式 深入浅出之——观察者模式

来源:恒创科技 编辑:恒创科技编辑部
2022-10-01 19:33:04


观察者模式

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

介绍

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。


设计模式 深入浅出之——观察者模式

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例:1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。

优点:1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点:1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

实现

观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建Subject类、Observer抽象类和扩展了抽象类Observer的实体类。

ObserverPatternDemo,我们的演示类使用Subject和实体类对象来演示观察者模式。

设计模式 深入浅出之——观察者模式_错误处理

模式一:接口的形式


#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: ErrorAbout
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ErrorAbout{

/// <summary>
/// 订阅者接口的集合
/// </summary>
private List<IHandle> handles = new List<IHandle>();

/// <summary>
/// 在主模块中可以通过此方法向 订阅者接口的集合 中添加新的订阅者(具体处理错误的方法)
/// </summary>
/// <param name="handle"></param>
public void AddErrorHanding(IHandle handle)
{
handles.Add(handle);
}

/// <summary>
/// 错误处理的方法,主模块中通过调用此方法来触发一系列的错误处理
/// </summary>
public void ErrorHanding()
{
//遍历订阅者接口的集合
foreach (var handle in handles)
{
//执行集合中的每个错误处理的方法
handle.ErrorHanding();
}
}
}

接口

#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: Ihandle
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IHandle{
void ErrorHanding();
}

实现接口类

#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: Handle
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HandleA : IHandle
{
public void ErrorHanding()
{
Debug.Log("出现错误!发送了一封邮件到管理员a");
}
}
public class HandleB : IHandle
{
public void ErrorHanding()
{
Debug.Log("出现错误!发送了一封邮件到管理员b");

}
}
public class HandleC : IHandle
{
public void ErrorHanding()
{
Debug.Log("出现错误!发送了一封邮件到管理员c");

}
}

调用

#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: Main
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在发布者类里有一个 List 存放观察者们。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
*/
public class Main : MonoBehaviour {

// Use this for initialization
void Start () {
//假设在这个位置,系统出现了错误,需要进行错误处理
Debug.Log("系统出现了严重错误,需要进行一些处理~~~");

//实例化错误处理相关的类(发布者)
ErrorAbout errorAbout = new ErrorAbout();
//向发布者添加订阅者
errorAbout.AddErrorHanding(new HandleA());
errorAbout.AddErrorHanding(new HandleB());
errorAbout.AddErrorHanding(new HandleC());
//只要发布者的方法一执行,所有订阅者的方法也都会被执行
errorAbout.ErrorHanding();

}
}
模式二:委托的形式

1.创建观察者,定义委托

#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: ErrorAbout
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public delegate void ErrorHandle();
namespace ObserverMode
{
public class ErrorAbout
{
//定义一个 具体错误处理方法委托 的变量
private ErrorHandle errorHandle;

//向外界提供一个可以向内部委托变量添加的方法
public void AddErrorHanding(ErrorHandle errorHandle)
{
//将传进来的方法加入委托变量中
if (this.errorHandle == null)
{
this.errorHandle = new ErrorHandle(errorHandle);
}
else
{
this.errorHandle += new ErrorHandle(errorHandle);
}
}

/// <summary>
/// 错误处理的方法,主模块中通过调用此方法来触发一系列的错误处理
/// </summary>
public void ErrorHanding()
{
//调用委托,相当于调用了委托中的所有方法
errorHandle();
}
}
}
#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: Handle
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ObserverMode
{
public class Handle1
{
public void ErrorHanding()
{
Debug.Log("出现错误!发送了一封邮件到管理员a!");
}
}
public class Handle2
{
public void ErrorHanding()
{
Debug.Log("出现错误!发送了一封邮件到管理员b!");
}
}
public class Handle3
{
public void ErrorHanding()
{
Debug.Log("出现错误!发送了一封邮件到管理员c!");
}
}
}
#region 模块信息
// **********************************************************************
// Copyright (C) 2018 Blazors
// Please contact me if you have any questions
// File Name: Main
// Author: romantic123fly
// WeChat||QQ: at853394528 || 853394528
// **********************************************************************
#endregion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ObserverMode
{
public class Main : MonoBehaviour
{
void Start()
{
//假设在这个位置,系统出现了错误,需要进行错误处理
Debug.Log("系统出现了严重错误,需要进行一些处理~~~");

//实例化错误处理相关的类(发布者)
ErrorAbout errorAbout = new ErrorAbout();
//向发布者添加订阅者
Handle1 handle1 = new Handle1();
errorAbout.AddErrorHanding(handle1.ErrorHanding);
Handle2 handle2 = new Handle2();
errorAbout.AddErrorHanding(handle2.ErrorHanding);
Handle3 handle3 = new Handle3();
errorAbout.AddErrorHanding(handle3.ErrorHanding);
//只要发布者的方法一执行,所有订阅者的方法也都会被执行
errorAbout.ErrorHanding();
}
}
}

​​源码地址链接​​


上一篇: 租用美国服务器:潜在的风险与应对策略。 下一篇: MongoDB 5.0 扩展开源文档数据库操作