设计模式--观察者模式

定义:

定义了对象之间一对多的关系,这样一来,当一个对象发生变化时,他的所有依赖者都会收到通知,并自动更新.

关键词:

observer : 观察者

subject : 主题

concreteObserver: 具体观察者

结构图:

image

应用场景:

当一个对象的状态变化时,需要通知其他多个对象进行同步更新时,可以使用此模式(如果有且只有一个对象需要更新,就没有必要了)

当需要动态增加删除需要同步的对象时

对象仅仅需要将自己的更新通知其他对象,而无需知道其他对象实现细节时.

优点:

subject 和 observer是高内聚,低耦合的,他们仅通过接口进行联系

无需指定具体的observer

缺点:

松耦合导致代码之间看起来关系不明显,比较难理解.

例子:

日志记录.当发生一个事件或者有状态变化时,需要日志记录下来.要求同时有数据库记录和文件记录.该如何写的?

通常写法是:

public class Record
{
    public void notify()
    {
        DatabaseLog d = new DatabaseLog();
        d.RecordToDataBase();

        FileLog f = new FileLog();
        f.RecordToFile();
    }
}

public class DatabaseLog
{
    public void RecordToDataBase()
    {
        //TODO
    }
}

public class FileLog
{
    public void RecordToFile()
    {
        //TODO
    }
}

当有变化时,页面上只需要调用

        Record r = new Record();
        r.notify();

即可.

但是:如果要求新增一种记录方式,web记录时,该如何处理呢?

新增一个WebLog类,然后修改Record类.

public class Record
{
    public void notify()
    {
        DatabaseLog d = new DatabaseLog();
        d.RecordToDataBase();

        FileLog f = new FileLog();
        f.RecordToFile();

        WebLog w = new WebLog();
        w.RecordToWeb();
    }
}

public class DatabaseLog
{
    public void RecordToDataBase()
    {
        //TODO
    }
}

public class FileLog
{
    public void RecordToFile()
    {
        //TODO
    }
}

public class WebLog
{
    public void RecordToWeb()
    {
        //TODO
    }
}
于是,我们发现:针对实际编程,每当有新增时,我们都需要添加新的记录类,并且修改Record类.
仔细观察三种记录方式,其实都是在对所发生的事情那个做记录,只是记录的方式不一样罢了.
类图:
image 
代码:
public interface ISubject
{
    void RegisterObserver(IObserver observer);

    void RemoveObserver(IObserver observer);

    void NotifyObservers();
}

public class Record : ISubject
{
    private ArrayList observersList;

    public Record()
    {
        observersList = new ArrayList();
    }

    public void RegisterObserver(IObserver observer)
    {
        observersList.Add(observer);
    }

    public void RemoveObserver(IObserver observer)
    {
        observersList.Remove(observer);
    }

    public void NotifyObservers()
    {
        foreach (IObserver observer in observersList)
        {
            observer.Record();
        }
    }

    public void SetEvent(int el)
    {
        if (el > 10)
        {
            NotifyObservers();
        }
    }
}

public interface IObserver
{
    void Record();
}

public class DatabaseLog : IObserver
{
    private ISubject subject;

    public DatabaseLog(ISubject subject)
    {
        this.subject = subject;
        subject.RegisterObserver(this);
    }

    public void Record()
    {
        //TODO
    }
}

public class FileLog : IObserver
{
    private ISubject subject;

    public FileLog(ISubject subject)
    {
        this.subject = subject;
        subject.RegisterObserver(this);
    }

    public void Record()
    {
        //TODO
    }
}

public class WebLog : IObserver
{
    private ISubject subject;

    public WebLog(ISubject subject)
    {
        this.subject = subject;
        subject.RegisterObserver(this);
    }

    public void Record()
    {
        //TODO
    }
}
页面调用:
    protected void Page_Load(object sender, EventArgs e)
    {
        Record r = new Record();

        DatabaseLog dbl = new DatabaseLog(r);
        FileLog fl = new FileLog(r);
        WebLog wl = new WebLog(r);

        r.SetEvent(100);
    }
此时,如果需要增加其他的记录方式的话,需要添加一个类实现Iobserver,然后还需要修改客户端页面.
通过配置文件,我们还可以使客户端做到易插拔.
<hr/>
以下来自<<深入浅出设计模式>>
 
涉及到的设计原则:
封装变化
    在观察者模式中,会改变的是主题(Subject)的状态,以及观察者(Observer)的数量和具体类型.
面向接口编程
    观察者和主题都使用接口,观察者使用主题的接口,主题使用观察者的接口.做到了松耦合.
优先使用对象组合,而不是继承
    观察者模式利用组合讲许多观察者组合进主题,对象之间的这种关系不是通过继承得到的,而是在运行时运用动态的组合生成的.
posted @ 2009-04-30 14:51  Localhost  阅读(265)  评论(0编辑  收藏  举报