观察者模式(Observer Pattern)
-
别名: 依赖,发布/订阅(Another Name: Dependents, Publish/Subscribe)
-
定义对象间的一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都得到通知并被自动更新。
-
何时使用
- 当一个对象的数据更新时,需要通知其他对象,而又不希望和被通知的对象形成紧耦合时
-
优点 ...
-
比如我们有个天气服务(主题),然后有多个使用它的客户端(观察者),包括android和iphone端app的服务(观察者),那么就可以使用这么模式。
我们需要一种结构存放天气信息(注意,省略了get、set方法!)
//天气的消息实体
public class WeatherInfo {
private long time;
private String weather;
public WeatherInfo(long time,String weather){
this.time = time;
this.weather = weather;
}
@Override
public boolean equals(Object obj) {
WeatherInfo info = (WeatherInfo) obj;
return info.time==this.time&&info.weather.equals(this.weather);
}
}
然后我们定义天气服务的接口(主题),以表示它应实现哪些功能:
//主题
public interface IWeatherService {
void addClient(Client client); //添加观察者
boolean deleteClient(Client client);//删除观察者
void notifyClients(); //通知
void updateWeather(WeatherInfo info);//主题内容更新
}
接着就是客户端的接口描述:
//观察者
public interface Client {
void getWeather(WeatherInfo info);
}
然后实现具体的天气服务,这里同样用到了单例模式:
//具体主题
public enum WeatherService implements IWeatherService{
instance;
private LinkedList<WeatherInfo> weatherInfos = new LinkedList<WeatherInfo>();
private LinkedHashSet<Client> clients = new LinkedHashSet<Client>(); //存放观察者
//添加观察者
@Override
public void addClient(Client client) {
clients.add(client);
}
//删除观察者
@Override
public boolean deleteClient(Client client) {
return clients.remove(client);
}
//通知观察者
@Override
public void notifyClients() {
Iterator<Client> iterator = clients.iterator();
while(iterator.hasNext()){
iterator.next().getWeather(weatherInfos.peekFirst());
}
}
//更新天气
@Override
public void updateWeather(WeatherInfo info) {
if(weatherInfos.size()>0)
if(weatherInfos.peekFirst().equals(info)) return;
weatherInfos.push(info);
if(clients.size()==0) return;
notifyClients();
}
}
最后就是具体的客户端(观察者,此处给出两个)
public class ClientAndroidServer implements Client {
private static String name = "安卓服务";
private WeatherInfo info;
@Override
public void getWeather(WeatherInfo info) {
this.info = info;
dealMsg();
}
private void dealMsg(){
System.out.println(name + "收到最新天气:time="+info.getTime()+"msg="+info.getWeather()+"。马上开始推送消息...");
}
}
public class ClientIphoneServer implements Client {
private static String name = "苹果服务";
private WeatherInfo info;
@Override
public void getWeather(WeatherInfo info) {
this.info = info;
dealMsg();
}
private void dealMsg(){
System.out.println(name + "收到最新天气:time="+info.getTime()+"msg="+info.getWeather()+"。马上开始推送消息...");
}
}
好,现在就可以直接使用了:
public class TestUse {
public static void main(String args[]){
//创建主题
WeatherService service = WeatherService.instance;
//添加观察者
service.addClient(new ClientAndroidServer());
service.addClient(new ClientIphoneServer());
//更新主题
service.updateWeather(new WeatherInfo(System.currentTimeMillis(), "多云"));
service.updateWeather(new WeatherInfo(System.currentTimeMillis()+1000*60*60*24, "多云转晴"));
service.updateWeather(new WeatherInfo(System.currentTimeMillis()+1000*60*60*24*2, "晴"));
}
}
运行后,控制台有如下输出
安卓服务收到最新天气:time=1461246047007msg=多云。马上开始推送消息...
苹果服务收到最新天气:time=1461246047007msg=多云。马上开始推送消息...
安卓服务收到最新天气:time=1461332447007msg=多云转晴。马上开始推送消息...
苹果服务收到最新天气:time=1461332447007msg=多云转晴。马上开始推送消息...
安卓服务收到最新天气:time=1461418847007msg=晴。马上开始推送消息...
苹果服务收到最新天气:time=1461418847007msg=晴。马上开始推送消息...
网友评论