DESIGN PATTERNS SAGA #20: REAL WORLD SITUATIONS WITH OBSERVER

Do you remember how to use the Swing API with action events? If not, refresh your memory here:

    // main method......
    someComponent.addActionListener(new ActionExample());

public class ActionExample implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        ...//code that reacts to the action...
    }
}

When using the Swing API you also use the Observer pattern maybe even without realizing it. The Observer pattern enables us to decouple the observed actions and isolate each process that must be executed. It’s clear that we will gain flexibility and cohesion.

observer_diagram.PNG

Get the Design_Patterns_Saga_GitHub_Source_Code

1 – Observer: It’s the generic abstract class that enables us to implement the Observer pattern. We will use the most powerful feature of Object Oriented programming, the Polymorphism. It’s crucial to fully master Polymorphism when using the Design Patterns.

public abstract class Observer {
	protected Subject subject;
	abstract void update();
}

2 – Subject: It orchestrates the necessary actions that must be executed when using the Observers. The Subject class contains the generic methods to be reused at the specific Subject class.

public abstract class Subject {

	private List<Observer> observers = new ArrayList<>();

	abstract void setState(String state);
	abstract String getState();

	public void attach(Observer observer) {
		observers.add(observer);
	}

	public void notifyObservers() {
		for (Observer observer : observers) {
			observer.update();
		}
	}
}

3 – Subject specialization: In this class, we are defining the specific actions to be executed by any Observer class.

public class MessageStream extends Subject {

	private Deque<String> messageHistory = new ArrayDeque<>();

	@Override
	void setState(String message) {
		messageHistory.add(message);
		this.notifyObservers();
	}

	@Override
	String getState() {
		return messageHistory.getLast();
	}
}

4 – Observers specializations: Finally the Observers’ implementations! Basically, to make everything work we add the subject in the Observers‘ constructors and invoke the addMessage method.

public class SlackClient extends Observer {

	public SlackClient(Subject subject) {
		this.subject = subject;
		subject.attach(this);
	}

	public void addMessage(String message) {
		subject.setState(message + " - sent from Slack");
	}

	@Override
	void update() {
		System.out.println("Slack Stream: " + subject.getState());
	}

} 

public class WhatsAppClient extends Observer {

	public WhatsAppClient(Subject subject) {
		this.subject = subject;
		subject.attach(this);
	}

	public void addMessage(String message) {
		subject.setState(message + " - sent from WhatsApp");
	}

	@Override
	void update() {
		System.out.println("WhatsApp Stream: " + subject.getState());
	}
}

5 – Unit Tests: Let’s see how it works. The use of the Observer pattern is pretty easy. Basically, we will instantiate the Subject specialization and pass it into the Observer specialization constructor. Then we will invoke the addMessage method and it’s done!

public class ObserverTest {

    @Test
    public void observerTest() {
        Subject subject = new MessageStream();

        WhatsAppClient whatsAppClient = new WhatsAppClient(subject);
        SlackClient slackClient = new SlackClient(subject);

        slackClient.addMessage("Another new message!");
        Assert.assertEquals("Another new message! " +
           "- sent from Slack", subject.getState());

        whatsAppClient.addMessage("Here is a new message!");
        Assert.assertEquals("Here is a new message! " +
           "- sent from WhatsApp", subject.getState());
    }

}

Summary of actions:

  1. Created the Observer abstract class
  2. Declared the Subject as a field inside the Observer abstract class
  3. Created the Subject abstract class
  4. Created the Subject specialization class
  5. Created the Observer specialization class
  6. Instantiated the Subject specialization class
  7. Created Observer specialization instances
  8. Passed the Subject instance to the Observer constructor
  9. Invoked the addMessage method from the Observers’ specialization

To practice the Observer pattern you can create another Subject or Observer. You could create a FileStreamSubject and InstagramClient, for example. It’s crucial to practice. Create at least one example and practice your programming skills using TDD!

DESIGN PATTERNS SAGA #20: REAL WORLD SITUATIONS WITH OBSERVER

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s