观察者模式:内部注册与外部注册

时间:2016-10-29 07:46:27

标签: java oop design-patterns

注册观察员的最佳选择是什么?我没有找到关于这个主题的任何内容。主要是" push vs. pull"讨论了,但也有一些注册观察者的选择。

public static void main(String[] args)
{
    Subject subject = new ConcreteSubject();
    // External registration
    Observer observerExternal = new ConcreteObserverExternal();
    subject.registerObserver(observerExternal);
    // Internal registration, option 1
    Observer observerInternal1 = new ConcreteObserverInternal1(subject);
    // Internal registration, option 2
    ConcreteObserverInternal2 observerInternal2 = new ConcreteObserverInternal2(subject);
}

interface Observer
{
    void inform();
}
class ConcreteObserverExternal implements Observer
{
    @Override
    public void inform()
    {
        // do sth.
    }
}
class ConcreteObserverInternal1 implements Observer
{
    public ConcreteObserverInternal1(Subject subject)
    {
        subject.registerObserver(this);
    }

    @Override
    public void inform()
    {
        // do sth.
    }
}
class ConcreteObserverInternal2
{
    public ConcreteObserverInternal2(Subject subject)
    {
        subject.registerObserver(() -> inform());
    }

    private void inform()
    {
        // do sth.
    }
}
interface Subject
{
    void registerObserver(Observer obs);

    void unregisterObserver(Observer obs);
}
class ConcreteSubject implements Subject
{
    @Override
    public void registerObserver(Observer obs)
    {
        // register
    }

    @Override
    public void unregisterObserver(Observer obs)
    {
        // unregister
    }

    private void foo()
    {
        // ...
        notifyObservers();
    }

    private void notifyObservers()
    {
        // notify observers
    }
}

我的代码中有三种情况:

  • 观察员在节目开始时注册,永远不会注册。在这种情况下,所有3个选项都是可能的。
  • 观察者在某处注册,并且在发生某些外部事件时需要取消注册。观察者不知道这个外部事件,显然必须在外部注册(选项1)。
  • 观察者在某处注册,并且在发生某些外部事件时需要取消注册。观察者知道发生了什么,因为它也是这个外部事件的观察者。在这种情况下,所有3个选项都是可能的。

在所有3个选项都可行的情况下,从OO和清洁代码的角度来看哪一个最好?

以下列出了我认为每个选项都有的优缺点。

1。外部注册

赞成
  - 观察者构造函数中的参数较少   - 主体不需要抽象,以促进主体和观察者之间的松散耦合。

缺点
  - 不要忘记在客户端代码中注册观察者。
  - 客户代码负责注册。

中性
  - 观察者有一个额外的公共方法   - Observer可以通过客户端代码注册/取消注册。

2。内部注册,选项1:具体观察者实现Observer接口

赞成
  - 观察员负责注册   - 注册不能忘记,因为一个人被迫将主题传递给观察者的构造函数。

缺点
  - 观察者的构造函数中的另一个参数。

中性
  - 观察者有一个额外的公共方法   - 观察者可以通过客户代码注册/取消注册   - 观察者可以注册/注销自己。

第3。内部注册,选项2:具体观察者不实施Observer接口

赞成
  - 观察员负责注册   - 注册不能忘记,因为一个人被迫将主题传递给观察者的构造函数。
  - 观察者没有额外的公共方法,可以被与#34;主题通知观察者"无关的任何东西滥用。

缺点
  - 观察者的构造函数中的另一个参数。

中性
  - 观察者只能注册/注销自己。

1 个答案:

答案 0 :(得分:1)

鉴于你在外部'之间提出的微妙差异。和'内部'注册,似乎没有一个正确的答案。不过,我会尝试。

我更喜欢'外部'注册其他两个有两个原因:

  • Observer不了解Subject s;即它们相当分离。例如,我可以将一个Observer附加到多个Subject,并且不会有任何人需要更改。
  • 更符合单一责任原则。 Observer仅关注inform时需要执行的操作。它并不关心注册/取消注册任何人。