观察者模式
问题场景
当一个类内部的数据出现某些变化的时候,其它类很感兴趣,它们想要即时得到那个类内部的数据发生变化时的通知。
总结模式
把那些对某一特定类型感兴趣的类型称为观察者,把特定类型称为发布者,观察者通过将自身封装成接口类型并注册到特定类型的接口列表中,当特定类型发生变化时,可通过遍历的形式去通知订阅者做出响应。
示例代码
namespace AppCUI
{
//观察者接口
public interface IObserver
{
//感兴趣的对象发生变化时我用Response做出响应
void Response( );
}
//发布者接口
public interface IPublish
{
void Register( IObserver observer ); //暴露此方法让观察者订阅我发布的主题
void Remove( IObserver observer ); //暴露此方法让观察者注销我发布的主题
void DataChange( ); //发布主题后通知观察者
}
//发布者
public class Publisher : IPublish
{
private List<IObserver> observeList;
public Publisher( )
{
observeList = new List<IObserver>( );
}
public void Register( IObserver observer )
{
observeList.Add( observer );
}
public void Remove( IObserver observer )
{
int index = observeList.IndexOf( observer );
if (index == -1) return;
observeList.RemoveAt( index );
}
public void DataChange( )
{
//为了便于理解,此处假装修改了Publisher的某个字段的值,导致DataChange被调用
//所以需要通知观察者做出响应
foreach (var observer in observeList)
{
observer.Response( );
}
}
}
//观察者
public class Person : IObserver
{
public void Response( )
{
Console.WriteLine( "我是Person,我知道你内部发生了变化,谢谢通知" );
}
}
//观察者2
public class Employee : IObserver
{
public void Response( )
{
Console.WriteLine( "我是Employee,我知道你内部发生了变化,谢谢通知" );
}
}
public class Programe
{
static void Main( string[] args )
{
Publisher publisher = new Publisher( );
Person person = new Person( );
Employee employee = new Employee( );
publisher.Register( person );
publisher.Register( employee );
//发布者发布了观察者感兴趣的主题
publisher.DataChange( );
}
}
}
{
//观察者接口
public interface IObserver
{
//感兴趣的对象发生变化时我用Response做出响应
void Response( );
}
//发布者接口
public interface IPublish
{
void Register( IObserver observer ); //暴露此方法让观察者订阅我发布的主题
void Remove( IObserver observer ); //暴露此方法让观察者注销我发布的主题
void DataChange( ); //发布主题后通知观察者
}
//发布者
public class Publisher : IPublish
{
private List<IObserver> observeList;
public Publisher( )
{
observeList = new List<IObserver>( );
}
public void Register( IObserver observer )
{
observeList.Add( observer );
}
public void Remove( IObserver observer )
{
int index = observeList.IndexOf( observer );
if (index == -1) return;
observeList.RemoveAt( index );
}
public void DataChange( )
{
//为了便于理解,此处假装修改了Publisher的某个字段的值,导致DataChange被调用
//所以需要通知观察者做出响应
foreach (var observer in observeList)
{
observer.Response( );
}
}
}
//观察者
public class Person : IObserver
{
public void Response( )
{
Console.WriteLine( "我是Person,我知道你内部发生了变化,谢谢通知" );
}
}
//观察者2
public class Employee : IObserver
{
public void Response( )
{
Console.WriteLine( "我是Employee,我知道你内部发生了变化,谢谢通知" );
}
}
public class Programe
{
static void Main( string[] args )
{
Publisher publisher = new Publisher( );
Person person = new Person( );
Employee employee = new Employee( );
publisher.Register( person );
publisher.Register( employee );
//发布者发布了观察者感兴趣的主题
publisher.DataChange( );
}
}
}
在C#中,已经有一个很好的解决思路,就是利用事件委托来实现这个发布-订阅的观察者模式。
namespace AppCUI
{
//发布者
public class Publisher
{
public event EventHandler Proxy;
public void DataChange( )
{
//为了便于理解,此处假装修改了Publisher的某个字段的值,导致DataChange被调用
//所以需要通知观察者做出响应
Proxy.Invoke( this, null );
}
}
//观察者
public class Person
{
public void Response( object sourceObject, EventArgs args )
{
Console.WriteLine( "我是Person,我知道你内部发生了变化,谢谢通知" );
}
}
//观察者2
public class Employee
{
public void Response( object sourceObject, EventArgs args )
{
Console.WriteLine( "我是Employee,我知道你内部发生了变化,谢谢通知" );
}
}
public class Programe
{
static void Main( string[] args )
{
Publisher publisher = new Publisher( );
Person person = new Person( );
Employee employee = new Employee( );
publisher.Proxy += person.Response;
publisher.Proxy += employee.Response;
//发布者发布了观察者感兴趣的主题
publisher.DataChange( );
}
}
}
{
//发布者
public class Publisher
{
public event EventHandler Proxy;
public void DataChange( )
{
//为了便于理解,此处假装修改了Publisher的某个字段的值,导致DataChange被调用
//所以需要通知观察者做出响应
Proxy.Invoke( this, null );
}
}
//观察者
public class Person
{
public void Response( object sourceObject, EventArgs args )
{
Console.WriteLine( "我是Person,我知道你内部发生了变化,谢谢通知" );
}
}
//观察者2
public class Employee
{
public void Response( object sourceObject, EventArgs args )
{
Console.WriteLine( "我是Employee,我知道你内部发生了变化,谢谢通知" );
}
}
public class Programe
{
static void Main( string[] args )
{
Publisher publisher = new Publisher( );
Person person = new Person( );
Employee employee = new Employee( );
publisher.Proxy += person.Response;
publisher.Proxy += employee.Response;
//发布者发布了观察者感兴趣的主题
publisher.DataChange( );
}
}
}