一、啥是观察者模式和WCF

1. 观察者模式

咱先说说观察者模式。这就好比你订阅了一份报纸,报社就是被观察的对象,而你就是观察者。当报社有新报纸出来的时候,就会主动给你送过来。在编程里,就是一个对象(被观察对象)状态发生变化时,会通知所有依赖它的对象(观察者)。这样可以让对象之间的耦合度降低,方便扩展。

2. WCF 是啥

WCF 呢,全称是 Windows Communication Foundation,是微软搞出来的一个框架,用来构建分布式应用程序。它能让不同的应用程序之间进行通信,就像不同城市的人打电话交流一样。WCF 支持多种协议,比如 HTTP、TCP 啥的,很灵活。

二、为啥要在 WCF 里用观察者模式实现服务事件实时通知

1. 应用场景

想象一下有这么个场景,你在开发一个股票交易系统。当某只股票的价格发生变化时,你得马上通知所有关注这只股票的用户。这时候,WCF 就可以作为服务器,和客户端进行通信,而观察者模式就能很好地实现股票价格变化的实时通知。

2. 优点和缺点

优点

  • 松耦合:观察者和被观察者之间的联系不那么紧密,修改一方不会对另一方产生太大影响。就像你换了一家报社订阅报纸,对报社来说只是少了一个订阅者,对其他订阅者没啥影响。
  • 可扩展性强:要是想增加新的观察者,很容易,直接加就行。比如股票交易系统里,有新用户关注某只股票,直接把他加到观察者列表里。
  • 实时通知:能及时把服务的状态变化通知给观察者。

缺点

  • 内存泄漏风险:如果观察者没有正确注销,会一直占用内存。就像你不看报纸了,但没有取消订阅,报社还一直给你送,占地方。
  • 性能问题:如果有大量的观察者,通知的时间会变长,影响性能。

三、具体咋实现

1. 定义服务契约

咱用 C# 来实现,这是一种常见的.NET 语言。下面是定义服务契约的代码:

// C# 技术栈
// 定义服务契约接口
using System.ServiceModel;

// 服务契约接口,用于定义服务的操作
[ServiceContract]
public interface IStockService
{
    // 订阅股票价格变化的方法
    [OperationContract]
    void Subscribe(IStockObserver observer);

    // 取消订阅股票价格变化的方法
    [OperationContract]
    void Unsubscribe(IStockObserver observer);

    // 模拟更新股票价格的方法
    [OperationContract]
    void UpdateStockPrice(string stockName, decimal price);
}

// 定义观察者接口
[ServiceContract]
public interface IStockObserver
{
    // 当股票价格变化时,调用此方法通知观察者
    [OperationContract(IsOneWay = true)]
    void StockPriceChanged(string stockName, decimal price);
}

在这段代码里,IStockService 是服务契约接口,定义了订阅、取消订阅和更新股票价格的方法。IStockObserver 是观察者接口,有一个 StockPriceChanged 方法,当股票价格变化时会调用这个方法通知观察者。

2. 实现服务

// C# 技术栈
using System;
using System.Collections.Generic;

// 服务实现类
public class StockService : IStockService
{
    // 存储观察者的列表
    private readonly List<IStockObserver> _observers = new List<IStockObserver>();

    // 实现订阅方法
    public void Subscribe(IStockObserver observer)
    {
        if (!_observers.Contains(observer))
        {
            _observers.Add(observer);
        }
    }

    // 实现取消订阅方法
    public void Unsubscribe(IStockObserver observer)
    {
        if (_observers.Contains(observer))
        {
            _observers.Remove(observer);
        }
    }

    // 实现更新股票价格方法
    public void UpdateStockPrice(string stockName, decimal price)
    {
        // 遍历所有观察者,通知他们股票价格变化
        foreach (var observer in _observers)
        {
            try
            {
                observer.StockPriceChanged(stockName, price);
            }
            catch (Exception ex)
            {
                // 处理异常,比如客户端连接断开
                Console.WriteLine($"Error notifying observer: {ex.Message}");
            }
        }
    }
}

StockService 类里,用一个列表 _observers 来存储所有的观察者。Subscribe 方法用来添加观察者,Unsubscribe 方法用来移除观察者,UpdateStockPrice 方法会遍历所有观察者,调用他们的 StockPriceChanged 方法通知股票价格变化。

3. 客户端代码

// C# 技术栈
using System;
using System.ServiceModel;

// 客户端观察者实现类
public class StockObserver : IStockObserver
{
    // 实现股票价格变化通知方法
    public void StockPriceChanged(string stockName, decimal price)
    {
        Console.WriteLine($"Stock {stockName} price changed to {price}");
    }
}

class Program
{
    static void Main()
    {
        // 创建服务代理
        var factory = new ChannelFactory<IStockService>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8080/StockService"));
        var service = factory.CreateChannel();

        // 创建观察者实例
        var observer = new StockObserver();

        // 订阅股票价格变化
        service.Subscribe(observer);

        // 模拟更新股票价格
        service.UpdateStockPrice("ABC", 100.50m);

        // 取消订阅
        service.Unsubscribe(observer);

        // 关闭服务代理
        ((ICommunicationObject)service).Close();

        Console.ReadLine();
    }
}

客户端代码里,StockObserver 类实现了 IStockObserver 接口,当收到股票价格变化通知时,会在控制台输出信息。在 Main 方法里,创建了服务代理,订阅了股票价格变化,模拟更新了股票价格,最后取消订阅。

四、注意事项

1. 异常处理

在通知观察者时,可能会出现异常,比如客户端连接断开。所以要在服务端做好异常处理,避免程序崩溃。就像上面代码里,在 UpdateStockPrice 方法里用 try-catch 块来捕获异常。

2. 线程安全

如果有多个线程同时访问观察者列表,可能会出现线程安全问题。可以使用锁机制来保证线程安全,比如在 SubscribeUnsubscribe 方法里加锁。

3. 资源管理

观察者在不需要接收通知时,要及时取消订阅,避免内存泄漏。就像你不看报纸了,要及时取消订阅。

五、总结

在 WCF 里应用观察者模式实现服务事件的实时通知,能让系统更灵活、可扩展,还能实现实时更新。但也有一些缺点,比如内存泄漏和性能问题,需要我们在开发过程中注意。通过上面的示例,我们可以看到具体的实现步骤,掌握了这些,就能在实际项目中运用这个技术了。