About the Program
It's a simple implementation of Observer Pattern.
The choice of different NotifyMethod
will affect how those observers are notified. The SimpleNotify
in blow just uses a simple for loop.
The concrete Observer is initialized with a concrete Observable that it want to observe. In the blow program concrete Observer = Reader
, and concrete Observable = Bookstore
.
Some Problems I've Noticed in the Program
A
Bookstore
instance is initialized with aNotifyMethod
instance, however to enable dynamic changing ofNotifyMethod
one have to "move" those readers from old method to new method.To make a class
Observable
, one has to modify the class (constructor, Observable's contracts), is it possible to make aBookstore
instance unaware of that it's being observed? i.e. How to design a class which can be changed from observable to not observable at runtime? Or this isn't an issue?The
Observer
interface isupdate()
without any arguments, so when implementing concrete Observer it has to keep a reference to a concrete Observable(Bookstore
in this case), and access theBookstore
's data by public interface. Is this a good idea? What's the drawback of this?
The Feature I want
From the current Observer interface, an concrete Observer can't observer multiple observables:
Person implements
BookstoreObserver, StockmarketObserver, ... {
bookstoreUpdate() { ... }
stockmarketUpdate() { ... }
...
}
If there are multiple Observer
interface then the update logic of each concrete Observable won't be lumped into the only one update()
if only one Observer
interface. Is this a good idea?
Finally, is it a good idea to make Reader
delegate its job to observe the Bookstore
instance to an Observer
? i.e. The Reader
also use composition like Bookstore
in the below program to achieve its Observer
effect?
The UML
Sorry for not showing much details, I used BlueJ and it can't show the interface/public methods of classes, but the code below is rather simple.
A typical Observer Pattern for reference.
Code
public interface Observable
{
public void register(Observer o);
public void unregister(Observer o);
public void sendNews();
}
public interface NotifyMethod extends Observable
{}
/**
* Use a simple for-each loop to send news to observers.
*/
public class SimpleNotify implements NotifyMethod
{
private List<Observer> observers = new ArrayList<Observer>();
public void register(Observer o) {
observers.add(o);
}
public void unregister(Observer o) {
observers.remove(o);
}
public void sendNews() {
for (Observer observer: observers) {
observer.update();
}
}
}
/**
* An observable bookstore.
*/
public class Bookstore implements Observable
{
private NotifyMethod notificationMethod;
private Book newBook;
//
public Bookstore(NotifyMethod notificationMethod) {
this.notificationMethod = notificationMethod;
}
public void publishNewBook(Book newBook) {
this.newBook = newBook;
sendNews();
}
public Book getNewBook() {
return newBook;
}
//
public void register(Observer o) {
notificationMethod.register(o);
}
public void unregister(Observer o) {
notificationMethod.unregister(o);
}
public void sendNews() {
notificationMethod.sendNews();
}
}
/**
* Book = "Title - Author"
*/
public class Book
{
private String title;
private String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
}
public interface Observer
{
public void update();
}
/**
* A Reader wants to observe the bookstore's news.
*/
public class Reader implements Observer
{
private String name;
private Bookstore bookstore;
//
public Reader(String name, Bookstore bookstore) {
this.name = name;
this.bookstore = bookstore;
bookstore.register(this);
}
public void update() {
System.out.format("Reader %s receives a book news \"%s - %s\"%n",
name,
bookstore.getNewBook().getTitle(),
bookstore.getNewBook().getAuthor());
}
}
Main Program and Output
public class Main
{
public static void main(String[] args) {
Bookstore myBookstore = new Bookstore(new SimpleNotify());
Reader MrA = new Reader("Mr.A", myBookstore);
Reader MrB = new Reader("Mr.B", myBookstore);
myBookstore.publishNewBook(new Book("Alice in Wonderland", "Lewis Carroll"));
}
}
Reader Mr.A receives a book news "Alice in Wonderland - Lewis Carroll"
Reader Mr.B receives a book news "Alice in Wonderland - Lewis Carroll"