定义
观察者定义了对象之间的一对多关系,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。
案例意图
- 一般主题只有一个,而观察者可以有多个。
- 观察者可以随时取消与主题的关系,而其它观察者并不受影响,主题也不受影响
算法优点
- 观察者和主题之间有很好的松耦合性,主题可以随时取消与观察者的联系,其他观察者并不会收到影响。
- 不需要知道观察者是怎样发生变化的,只需要推送信息即可。
算法缺点
- 若观察者太多,每个都通知则会浪费大量的时间。
- 若观察者之间存在循环调用,则会造成崩溃。
实现方式
- 定义某个抽象,让观察者继承或实现该抽象,主题存有观察者列表(列表中的对象都继承或实现同一抽象),当主题发生变化时,挨个通知观察者。
- C#的委托
代码实现
- 方式一
namespace Algorithm.Design
{
class ObserverMode
{
public static void Main()
{
SubjectInterface subject = new Subject(); //主题
ObserverInterface one = new ObserverOne(subject); //观察者
ObserverInterface two = new ObserverTwo(subject);
Run(subject);
two.Remove();
Console.WriteLine("-==========================");
Run(subject);
}
public static void Run(SubjectInterface subject)
{
for (int i = 0; i < 100; i++)
{
if (i == 44)
{
subject.NotifyObserver(i);//通知观察者
break;
}
}
}
}
public interface ObserverInterface
{
void Update(int time);
void Remove();
}
public interface SubjectInterface
{
void AddObserver(ObserverInterface o);
void RemoveObserver(ObserverInterface o);
void NotifyObserver(int time);
}
public class Subject : SubjectInterface
{
List<ObserverInterface> observerList = new List<ObserverInterface>(); //观察者列表
public Subject() { }
public void AddObserver(ObserverInterface o) //加入观察者
{
observerList.Add(o);
}
public void NotifyObserver(int time) //通知
{
foreach(ObserverInterface o in observerList)
{
if(o != null)
{
o.Update(time);
}
}
}
public void RemoveObserver(ObserverInterface o)//移除
{
if (observerList.Contains(o))
{
observerList.Remove(o);
}
}
}
public class ObserverOne:ObserverInterface
{
SubjectInterface subject;
public ObserverOne(SubjectInterface subject)
{
this.subject = subject;
this.subject.AddObserver(this);
}
public void Update(int time)
{
Console.WriteLine("ObserverOne ==" + time);
}
public void Remove() //移除自身
{
subject?.RemoveObserver(this);
}
}
public class ObserverTwo : ObserverInterface
{
SubjectInterface subject;
public ObserverTwo(SubjectInterface subject)
{
this.subject = subject;
this.subject.AddObserver(this);
}
public void Update(int time)
{
Console.WriteLine(time +" = ObserverTwo ==" + time);
}
public void Remove()
{
subject?.RemoveObserver(this);
}
}
}
- 方式二
namespace Algorithm.Design
{
class ObserverMode2
{
public static void Main()
{
Subject2 subject = new Subject2();
ObserverOne2 one = new ObserverOne2();
ObserverTwo2 two = new ObserverTwo2();
subject.AddObserver(one.Update);
subject.AddObserver(two.Update);
Run(subject);
Console.WriteLine("-==========================");
subject.RemoveObserver(two.Update);
Run(subject);
}
public static void Run(Subject2 subject)
{
for (int i = 0; i < 100; i++)
{
if (i == 44)
{
subject.NotifyObserver(i);//通知观察者
break;
}
}
}
}
public delegate void Update(int time); //定义委托
public class Subject2
{
public event Update update;
public void AddObserver(Update u)
{
if(update == null) //没初始化先初始化
{
update = new Update(u);
}
else //否则之间添加
{
update += u;
}
}
public void NotifyObserver(int time)
{
if(update != null)
{
update(time);
}
}
public void RemoveObserver(Update u)
{
if(update != null)
{
update -= u;
}
}
}
public class ObserverOne2
{
public void Update(int time)
{
Console.WriteLine("ObserverOne ==" + time);
}
}
public class ObserverTwo2
{
public void Update(int time)
{
Console.WriteLine(time + " = ObserverTwo ==" + time);
}
}
}
- Subject2中保留了一个Update的委托对象,前面添加event的作用是使该类有更好的封装性。
- 事件(event)封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同
- 避免在类外面以subject.update(2)这类的不恰当的形式直接触发委托。因为event只允许出现在+=和-=的左边,使类有更好的封装性。