设计模式(18)观察者模式

模式介绍

观察者模式试图允许对象在其内部状态改变时通知观察者。

这意味着单个对象需要知道观察它的对象,并且当状态发生变化的时候,需要能够与那些观察者通信。此外,观察者应该被自动通知。

示例

设想我们需要一个系统来建模本地蔬菜市场中蔬菜价格的波动。
我们需要允许餐馆查看价格,并在特定蔬菜的价格低于指定阈值时下订单,这对于每个餐馆来说都是不同的。

抽象的蔬菜类:

/// <summary>
/// The Subject abstract class
/// </summary>
abstract class Veggies
{
    private double _pricePerPound;
    private List<IRestaurant> _restaurants = new List<IRestaurant>();

    public Veggies(double pricePerPound)
    {
        _pricePerPound = pricePerPound;
    }

    public void Attach(IRestaurant restaurant)
    {
        _restaurants.Add(restaurant);
    }

    public void Detach(IRestaurant restaurant)
    {
        _restaurants.Remove(restaurant);
    }

    public void Notify()
    {
        foreach (IRestaurant restaurant in _restaurants)
        {
            restaurant.Update(this);
        }

        Console.WriteLine("");
    }

    public double PricePerPound
    {
        get { return _pricePerPound; }
        set
        {
            if (_pricePerPound != value)
            {
                _pricePerPound = value;
                Notify(); //Automatically notify our observers of price changes
            }
        }
    }
}

具体的蔬菜类-胡萝卜:

/// <summary>
/// The ConcreteSubject class
/// </summary>
class Carrots : Veggies
{
    public Carrots(double price) : base(price) { }
}

抽象的餐馆:

/// <summary>
/// The Observer interface
/// </summary>
interface IRestaurant
{
    void Update(Veggies veggies);
}

具体的餐馆:

/// <summary>
/// The ConcreteObserver class
/// </summary>
class Restaurant : IRestaurant
{
    private string _name;
    private Veggies _veggie;
    private double _purchaseThreshold;

    public Restaurant(string name, double purchaseThreshold)
    {
        _name = name;
        _purchaseThreshold = purchaseThreshold;
    }

    public void Update(Veggies veggie)
    {
        Console.WriteLine("Notified {0} of {1}'s " + " price change to {2:C} per pound.", _name, veggie.GetType().Name, veggie.PricePerPound);
        if(veggie.PricePerPound < _purchaseThreshold)
        {
            Console.WriteLine(_name + " wants to buy some " + veggie.GetType().Name + "!");
        }
    }
}

客户端调用:

static void Main(string[] args)
{
    // Create price watch for Carrots and attach restaurants that buy carrots from suppliers.
    Carrots carrots = new Carrots(0.82);
    carrots.Attach(new Restaurant("Mackay's", 0.77));
    carrots.Attach(new Restaurant("Johnny's Sports Bar", 0.74));
    carrots.Attach(new Restaurant("Salad Kingdom", 0.75));

    // Fluctuating carrot prices will notify subscribing restaurants.
    carrots.PricePerPound = 0.79;
    carrots.PricePerPound = 0.76;
    carrots.PricePerPound = 0.74;
    carrots.PricePerPound = 0.81;

    Console.ReadKey();
}

总结

观察者模式是常用的设计模式之一,简单来说就是,如果主体改变了,观察者需要知道它。

源代码

https://github.com/exceptionnotfound/DesignPatterns/tree/master/Observer

原文

https://www.exceptionnotfound.net/the-daily-design-pattern-observer/