【问题标题】:Observer with full transparency完全透明的观察者
【发布时间】:2021-02-20 16:29:31
【问题描述】:

我正在通过以下方式实现观察者模式:

interface Layer{
    void adjustString(Set<String> strings);
}

interface NotifiableLayer extends Layer{
    void layerAdjusted(Layer layer);
}

abstract class ObservableLayer implements Layer{
    Set<NotifiableLayer> observers = new HashSet<>();

    void addObserver(NotifiableLayer layer){
        observers.add(layer);
    }
    void removeObserver(NotifiableLayer layer){
        observers.remove(layer);
    }

    void notifyObservers(){
        observers.forEach(l -> l.layerAdjusted(this));
    }
}

class MyLayer extends ObservableLayer{
    @Override
    public void adjustString(Set<String> strings) {
        this.notifyObservers(); //can this be auto?
    }
}

这当然可行,但是实现ObservableLayer 的人需要记住在adjustString 方法中调用this.notifyObservers()。这没什么大不了的,但我想看看有没有办法完全隐藏它。

到目前为止,我只有这个想法(使用模板方法):

abstract class ObservableLayer implements Layer{
    //...methods removed for simplicity

    @Override
    public void adjustString(Set<String> strings) {
        this.doAdjustString(strings);
        this.notifyObservers(); //<---- here is auto
    }

    abstract void doAdjustString(Set<String> strings);
}

class MyLayer extends ObservableLayer{
    @Override
    public void doAdjustString(Set<String> strings) {
        //now notification is in base adjustString
    }
}

但是这里我不喜欢把那个方法名改成doAdjustString,而且其他层实现之间不再统一(直接实现Layer接口的层)。

有没有简单的方法来拥有这个功能,但要在MyLayer 类中保留public void adjustString(Set&lt;String&gt; strings) 签名?

【问题讨论】:

    标签: java oop design-patterns observer-pattern template-method-pattern


    【解决方案1】:

    一种方法是使用一个包含ObservableLayer 实例并委托给它的装饰器实例。

        final class LayerDecorator implements Layer {
          final private ObservableLayer delegate;
    
          public LayerDecorator(ObservableLayer delegate) {
            this.delegate = delegate;
          }
    
          @Override
          public void adjustString(Set<String> strings) {
            delegate.adjustString(strings);
            delegate.notifyObservers();
          }
        }
    

    这假定调用代码正在使用对Layer 的引用而不是ObservableLayer

    如果调用代码必须使用对ObservableLayer 的引用,那么最好将ObservableLayer 重构为具有注册侦听器、删除它们并通知它们的方法的接口。该接口还扩展了Layer 接口。

       interface IObservableLayer extends Layer {
         void addObserver(NotifiableLayer layer);
         void removeObserver(NotifiableLayer layer);
         void notifyObservers();
       }
    

    抽象类ObservableLayer 改为实现IObservableLayer,而不是直接实现Layer。该类仍然是公开的,以支持应用程序类定义可观察层的变体。

    接下来可以为可观察层定义一个内部装饰器,如下所示。

        final class ObservableLayerDecorator implements IObservableLayer {
          final private ObservableLayer delegate;
    
          public ObservableLayerDecorator(ObservableLayer delegate) {
            this.delegate = delegate;
          }
    
          @Override
          public void addObserver(NotifiableLayer layer) {
            delegate.addObserver(layer);
          }
    
          @Override
          public void removeObserver(NotifiableLayer layer) {
            delegate.removeObserver(layer);
          }
    
          @Override
          public void notifyObservers() {
            delegate.notifyObservers();
          }
    
          @Override
          public void adjustString(Set<String> strings) {
            delegate.adjustString(strings);
            this.notifyObservers();
          }
        }
    

    请注意在这种情况下通知是如何完成的。

    现在IObservableLayer 的实例可以创建为

        IObservableLayer observableLayer = new ObservableLayerDecorator(new MyClass());
    

    工厂方法在这里会很有帮助,因为它们可以被定义为处理各种应用程序级可观察层类的创建,以便可以一致地创建实例,返回一个被修饰的IObservableLayer。这将使开发人员无需了解如何使用装饰器,并允许装饰器成为内部实用程序。

    【讨论】:

    • 感谢您提供另一种方法 - 标准“优先组合优于继承”。
    【解决方案2】:

    另一种方法是面向方面的编程。

    以下示例使用 AspectJ 拦截在扩展 Observable 的类上执行的任何 public 方法,并在同一对象上调用 notifyObservers()

    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class EventAspect {
        @AfterReturning("execution(public * Observable.*(..)) && target(observable)")
        public void notifyObservers(Observable observable) {
            observable.notifyObservers();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 2023-04-10
      相关资源
      最近更新 更多