Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid exposing implementation details when implementing an observer pattern in Java?

I'm coming to Java from C# where events are first class citizens and event handlers can be private methods. I'm now working on a Java project where I of course need to use an Observer pattern to implement eventing.

Since the Observer needs to expose its listener/handler callback methods to the Observable class, it seems that this is exposing implementation of the details of the Observer to other unconcerned classes. I can set the access to these methods to the package level which would keep these implementation details hidden to consumers of my package, but it still has a bad "smell" to me.

Is this just something I need to grit my teeth and bare or is there a better way?

like image 961
HolySamosa Avatar asked Jan 06 '12 21:01

HolySamosa


2 Answers

With the Observer pattern your classes which are observing do not need to expose their implementations. Often your class which is notifying other classes will have its own associated interface for those other classes to implement.

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

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

Any class can implement the Observer interface and register itself without exposing any implementation details. It does expose that it implements an interface, but that does not specify how it implements it. Alternatively, you could provide an anonymous implementation.

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

Update If you are concerned that your class now is exposing a new interface there are some ways to work around it. One is to create an anonymous implementation. Another is that you can have a private internal class which implements the Observable interface.

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

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

To use an anonymous implementation:

theObservable.register(new Observer()
            {
                public void handleSomeEvent(Object someObjectOfImportance)
                {
                                // ...
                }
            });
like image 153
David V Avatar answered Nov 01 '22 20:11

David V


In Java this is normally not thought of as really exposing implementation details, however, if you really want to hide the functionality of your class from other classes then you need to have your class implement different interfaces that each only expose a subset of the overall class functionality. If you then ensure that other classes only access your class through a particular interface (possibly via a factory) then you effectively hide your implementation.

E.g:

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();
  }
}
like image 1
Trevor Freeman Avatar answered Nov 01 '22 18:11

Trevor Freeman