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

Seb*_*ebi 7 java oop design-patterns

注册观察员的最佳选择是什么?我没有找到关于这个主题的任何内容。主要讨论了“推与拉”,但也有几个选项可以注册观察者。

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
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是我的代码中的三种情况:

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

在所有 3 个选项都可能的情况下,从面向对象和干净代码的角度来看,哪一个是最好的?

这是我认为每个选项都有的一些优点和缺点的列表。

1.外部注册

优点
- 观察者的构造函数中的参数较少。
- 不需要对Subject 进行抽象以促进Subject 和Observer 之间的松散耦合。

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

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

2.内部注册,方案一:具体的observer实现Observer接口

优点
- 观察者负责注册。
- 注册不能忘记,因为必须将Subject 传递给Observer 的构造函数。

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

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

3.内部注册,选项2:具体观察者不实现观察者接口

优点
- 观察者负责注册。
- 注册不能忘记,因为必须将Subject 传递给Observer 的构造函数。
- 观察者没有额外的公共方法可以被与“主题通知观察者”无关的任何东西滥用。

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

中立
- 观察者只能注册/取消注册自己。

ket*_*iya 1

鉴于您提出的“外部”和“内部”注册之间的细微差别,看起来似乎没有一个正确的答案。尽管如此,我还是会尝试。

与其他两个相比,我更喜欢“外部”注册,原因有两个:

  • sObserver对 s 一无所知Subject;即,它们是相当解耦的。例如,我可以将一个附加Observer到多个Subjects,并且无需任何人进行更改。
  • 更符合单一职责原则。唯一Observer关心的是编辑时需要做什么inform。它不关心向任何人注册/注销。