Skip to main content

Design Pattern: Observer Pattern

Free2015-03-06#Design_Pattern#观察者模式#Observer Strategy

The Observer Pattern, summarized in one sentence, is defining and maintaining a one-to-many relationship between objects. "Defining" refers to establishing a dependency relationship between the "one" and the "many"; "Maintaining" refers to our ability to dynamically remove dependencies and establish new dependencies.

no_mkd

I. What is the Observer Pattern?

Abstracting the relationship between newspapers and subscribers in the real world gives us the Observer Pattern. One newspaper corresponds to multiple subscribers; subscribers can unsubscribe at any time, and unsubscribed readers can also start subscribing at any time. Once a new newspaper is published, all subscribers will receive the new content.

In the Observer Pattern, the newspaper is called the Subject, and the subscriber is called the Observer. One Subject can be observed by multiple Observers; Observers can stop observing at any time, and new Observers can also start observing the Subject at any time. When the Subject's content changes, it will notify all Observers.

II. An Example

Many online games have quiz activities. All players participating in the quiz activity will receive the question information simultaneously (delay is negligible). Players not participating in the activity can join midway, and players currently answering can exit at any time. In this example, the game server is the "one", the players are the "many", and the question information is the message passed between them. How can we design classes to meet the above requirements? Let's try the Observer Pattern.

First, define the Subject abstract class:

package ObserverPattern;

import java.util.ArrayList;

/**

  • @author ayqy
  • 定义 Subject 抽象类

*/ public abstract class Subject { ArrayList<Observer> observers = new ArrayList<Observer>();//观察者列表

/**
 * 注册主题
 * @param o 申请注册该主题的 Observer
 */
public void registSubject(Observer o)
{
	observers.add(o);
}

/**
 * 删除主题
 * @param o
 */
public void reomveSubject(Observer o)
{
	int index = observers.indexOf(o);
	observers.remove(index);
}

/**
 * 通知所有观察者
 * @param arg 该 Subject 想要传递给 Observers 的数据
 */
public void notifyObservers(Object arg)
{
	for(Observer o : observers)
	o.update(this, arg);
}

}

Note, here we use an abstract class instead of an interface, why? Because the Subject's behavior is fixed, and does not need to be extended by subclasses. Similarly, we define the Observer abstract class:

package ObserverPattern;

/**

  • @author ayqy
  • 定义 Observer 抽象类

*/ public abstract class Observer { Subject subject = null;//定义该 Observer 所关注的 Subject

public abstract void update(Subject subject, Object arg);//定义 Observer 的更新接口

}

Now let's implement our custom Subject——GameServer:

package ObserverPattern;

/**

  • @author ayqy
  • 定义 GameServer 类,继承自 Subject 基类,负责发布题目

*/ public class GameServer extends Subject{ Question ques;//定义题目

public Question getQues() {
	return ques;
}

public void setQues(Question q) {
	this.ques = q;
	
	super.notifyObservers(ques);//调用父类方法通知所有 Observer
}

}

P.S. The member variable Question of the GameServer class is a simple encapsulation of question information. The Question class contains two parts of definition: question number no and question content content, as well as a toString method, returning the question description information. Now implement our custom Observer——Player:

package ObserverPattern;

/**

  • @author ayqy
  • 定义 PlayerA,继承自 Observer 基类,负责接收新题目

*/ public class PlayerA extends Observer{

public PlayerA(Subject sub)
{
	subject = sub;
}

 @Override
public void update(Subject subject, Object arg) {
	Question q = (Question)arg;
	System.out.println("PlayerA received " + q.toString());
}

}

P.S. To make the class hierarchy clearer, we did not define a Player base class here. It is easy to copy and paste to get PlayerB and PlayerC, no need to elaborate.

At this point, our simulation of the quiz activity preparation is over. Next, we need to define a test class to demonstrate the charm of the Observer Pattern.

III. Effect Example

Define the following Test class:

package ObserverPattern;

/**

  • @author ayqy
  • 实现一个测试类,模拟网络游戏答题活动(游戏服务器按时更新题目信息并通知所有参与答题的玩家)

*/ public class Test { public static void main(String[] args) { System.out.println("答题活动即将开始。。"); //创建服务器 GameServer gs = new GameServer(); //创建玩家 ABC Observer playerA = new PlayerA(gs); Observer playerB = new PlayerB(gs); Observer playerC = new PlayerC(gs); //为 AB 注册 Subject,C 对答题不感兴趣,拒绝注册 gs.registSubject(playerA); gs.registSubject(playerB); System.out.println("玩家 AB 成功参与答题活动。。"); System.out.println("答题活动正式开始。。"); gs.setQues(new Question(1, "第一题")); gs.setQues(new Question(2, "第二题")); System.out.println("玩家 A 不想玩了,退出答题活动。。"); gs.reomveSubject(playerA); gs.setQues(new Question(3, "第三题")); System.out.println("玩家 C 想中途加入活动"); gs.registSubject(playerC); gs.setQues(new Question(4, "第四题")); System.out.println("答题活动结束。。"); } }

Result example:

IV. Summary

From the example above, we can see the characteristics of the Observer Pattern:

  1. Using the Observer Pattern, it is easy to establish a "one-to-many" dependency relationship between objects;
  2. Using the mechanism of the Observer Pattern, it is easy to implement dynamic maintenance of this dependency relationship

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment