观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,
当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在抽象类里有一个 ArrayList 存放观察者们。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
观察者模式包含以下几个核心角色:
主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。
观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。
具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。
该实例基于WPF实现,直接上代码,下面为三层架构的代码。
一 Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.观察者模式
{
//2,订阅者接口
public interface IObserver
{
void ReceiveAndPrint(Tenxun tenxun);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.观察者模式
{
//具体的订阅者类
public class Subscriber : IObserver
{
public string Name { get; set; }
public string SubInfo { get; set; }
public Subscriber(string name)
{
Name = name;
}
public void ReceiveAndPrint(Tenxun tenxun)
{
SubInfo = $"name:{Name},symbol:{tenxun.Symbol},info:{tenxun.Info} \r\n";
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.观察者模式
{
//1,订阅号抽象类
public abstract class Tenxun
{
//保存订阅者列表
private List<IObserver> observers = new List<IObserver>();
public string Symbol { get; set; }
public string Info { get; set; }
protected Tenxun(string symbol, string info)
{
Symbol = symbol;
Info = info;
}
//新增对订阅号列表的维护操作
public void AddObserver(IObserver observer)
{
observers.Add(observer);
}
//删除对订阅号列表的维护操作
public void RemoveObserver(IObserver observer)
{
observers.Remove(observer);
}
//通知更新:遍历订阅者列表进行通知
public void Update(ref List<IObserver> os)
{
foreach (IObserver observer in observers)
{
if (observer != null)
{
observer.ReceiveAndPrint(this);
}
}
os = observers;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式练习.Model.观察者模式
{
//3,具体订阅号类
public class TenXunGame : Tenxun
{
public TenXunGame(string symbol, string info) : base(symbol, info)
{
}
}
}
二 View
<Window x:Class="设计模式练习.View.观察者模式.ObserverWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:设计模式练习.View.观察者模式"
mc:Ignorable="d"
Title="ObserverWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Res1}" TextWrapping="Wrap" Grid.Row="0"/>
<TextBlock Text="{Binding Res2}" TextWrapping="Wrap" Grid.Row="1"/>
<TextBlock Text="{Binding Res3}" TextWrapping="Wrap" Grid.Row="2"/>
<TextBlock Text="{Binding Res4}" TextWrapping="Wrap" Grid.Row="3"/>
</Grid>
<Button Content="随机变化,发布消息" Grid.Column="1" Command="{Binding subCommand}"/>
</Grid>
</Window>
三 ViewModel
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 设计模式练习.Model.观察者模式;
namespace 设计模式练习.ViewModel.观察者模式
{
partial class ObserverWindow_ViewModel : ObservableObject
{
Tenxun[] tenxun = null;
public ObserverWindow_ViewModel()
{
Tenxun t = new TenXunGame("地下城", "这是一款非常好玩的游戏.....");
//添加订阅者
t.AddObserver(new Subscriber("李军军"));
t.AddObserver(new Subscriber("Hars"));
t.AddObserver(new Subscriber("大兵"));
t.AddObserver(new Subscriber("泰戈尔"));
Tenxun t2 = new TenXunGame("英雄联盟", "体现男人的英雄气概");
//添加订阅者
t2.AddObserver(new Subscriber("富家子弟"));
t2.AddObserver(new Subscriber("穷小子"));
t2.AddObserver(new Subscriber("瓜瓜多尔"));
t2.AddObserver(new Subscriber("先去布尔顿"));
Tenxun t3 = new TenXunGame("QQ炫舞", "展示女孩子的多才多艺.....");
//添加订阅者
t3.AddObserver(new Subscriber("小兰花"));
t3.AddObserver(new Subscriber("frewsa"));
t3.AddObserver(new Subscriber("小湖北"));
t3.AddObserver(new Subscriber("瓜子农民"));
Tenxun t4 = new TenXunGame("帝国制造者", "放眼国际,谁与争锋.....");
//添加订阅者
t4.AddObserver(new Subscriber("贵价家"));
t4.AddObserver(new Subscriber("富可视"));
t4.AddObserver(new Subscriber("军成家"));
t4.AddObserver(new Subscriber("越南谢尔顿"));
tenxun = new Tenxun[] { t, t2, t3, t4 };
}
[ObservableProperty]
private string res1;
[ObservableProperty]
private string res2;
[ObservableProperty]
private string res3;
[ObservableProperty]
private string res4;
[RelayCommand]
private void sub()
{
int index = new Random().Next(0, tenxun.Length);
Tenxun t = tenxun[index];
List<IObserver> list = null;
t.Update(ref list);
Res1 = (list[0] as Subscriber).SubInfo;
Res2 = (list[1] as Subscriber).SubInfo;
Res3 = (list[2] as Subscriber).SubInfo;
Res4 = (list[3] as Subscriber).SubInfo;
}
}
}