Избегать раскрытия деталей реализации при реализации шаблона наблюдателя в Java? - PullRequest
7 голосов
/ 07 января 2012

Я прихожу на Java из C #, где события являются гражданами первого класса, а обработчики событий могут быть закрытыми методами. Сейчас я работаю над проектом Java, где мне, конечно, нужно использовать шаблон Observer для реализации событий.

Так как Observer необходимо предоставить свои методы обратного вызова слушателя / обработчика классу Observable, кажется, что это подвергает реализацию деталей Observer другим не связанным классам. Я могу установить доступ к этим методам на уровне пакета, чтобы эти детали реализации были скрыты для потребителей моего пакета, но он все еще имеет неприятный «запах» для меня.

Мне просто нужно стиснуть зубы и обнажить или есть лучший способ?

Ответы [ 2 ]

9 голосов
/ 07 января 2012

С шаблоном Observer ваши классы, которые наблюдают, не должны показывать свои реализации.Часто ваш класс, который уведомляет другие классы, будет иметь свой собственный связанный интерфейс для реализации этими другими классами.

public interface Observer
{
    public void handleSomeEvent(Object someObjectOfImportance);
}

public class Observable
{
    public void register(Observer observer);
}

Любой класс может реализовать интерфейс Observer и зарегистрировать себя, не раскрывая никаких деталей реализации.Он показывает, что он реализует интерфейс, но это не определяет , как он реализует его.В качестве альтернативы вы можете предоставить анонимную реализацию.

public class SomeObserverImplementation implements Observer
{
    public void handleSomeEvent(Object someObjectOfImportance)
    {
        // I can do whatever I want here
    }
}

Обновление Если вы обеспокоены тем, что ваш класс теперь предоставляет новый интерфейс , есть несколько способов работывокруг него.Одним из них является создание анонимной реализации.Другой способ заключается в том, что у вас может быть закрытый внутренний класс, который реализует интерфейс Observable.

public class IDontWantOthersToKnowIObserve
{
    private class HiddenObserver implements Observer
    {
        public void handleSomeEvent(Object someObjectOfImportance)
        {
           ...
        }
    }

    ... in some method ...
    theObservable.register(myHiddenObserver);
}

Чтобы использовать анонимную реализацию:

theObservable.register(new Observer()
            {
                public void handleSomeEvent(Object someObjectOfImportance)
                {
                                // ...
                }
            });
1 голос
/ 07 января 2012

В Java это обычно не рассматривается как фактическое раскрытие деталей реализации, однако, если вы действительно хотите скрыть функциональность вашего класса от других классов, тогда вам нужно, чтобы ваш класс реализовывал различные интерфейсы, каждый из которых предоставляет только подмножествообщий класс функциональности.Если вы затем убедитесь, что другие классы получают доступ к вашему классу только через определенный интерфейс (возможно, через фабрику), то вы фактически скрываете свою реализацию.

Например:

public interface Observer<T>
{
  public void notify(T event);
}

public interface PublicFace
{
  public void doSomething();
}

public class SomeClass implements Observer<Event>, PublicFace
{
  public void notify(Event event)
  { 
    // ...
  }

  public void doSomething()
  {
    // ...
  }
}

public class FaceFactory
{
  public static PublicFace getPublicFaceInstance()
  {
    return new SomeClass();
  }
}
...