设计模式---观察者模式(Observer Pattern with java)

本文深入探讨了观察者模式的概念、原理及其在面向对象编程中的实际应用,通过实例展示了如何使用该模式简化事件处理逻辑,提高代码的可读性和可维护性。同时,介绍了观察者模式在AWT事件处理中的应用,以及如何通过接口实现更加灵活的事件监听机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

观察者模式(有时又被称为发布/订阅模式)是软体设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。

先看一个例子

有个小孩在睡觉,醒来之后要喂奶。

我们使用的是java,所以不要闹出下面的笑话(披着面向对象的面向过程):

public class simulation {

public static void main(string... args) {

//小孩睡觉

//起来之后爸爸喂奶

//...

}

}

我们根据面向对象思想,加上多线程模拟child和dad,小孩在睡觉,随时可以起来,dad隔一段时间看下小孩是否醒来。

package observer;

import java.util.random;

class child implements runnable {

public static random r = new random();

private boolean wake = false;

public child() {

new thread(this).start();

}

@override

public void run() {

while (!wake) {

system.out.println("child:i am sleeping...");

try {

thread.sleep(1000);

} catch (interruptedexception e) {

e.printstacktrace();

}

if (r.nextint(10) > 8) {

wakeup();

}

}

}

public void wakeup() {

wake = true;

}

public boolean iswake() {

return wake;

}

}

class dad implements runnable {

private child c;

public dad(child c) {

new thread(this).start();

this.c = c;

}

@override

public void run() {

while (!c.iswake()) {

system.out.println("dad:child is sleeping...");

try {

thread.sleep(1000);

} catch (interruptedexception e) {

e.printstacktrace();

}

}

feed(c);

}

private void feed(child c2) {

system.out.println("feed child!");

}

}

public class firstquestion {

public static void main(string[] args) {

new dad(new child());

}

}

这样可以实现功能,但造成资源的浪费。开了这么多线程,dad时间都用在看小孩身上了,dad下午打牌的计划泡汤了。我们可以很容易的把dad解放出来:

class child implements runnable {

public static random r = new random();

private dad d;

private boolean wake = false;

public child(dad d) {

this.d = d;

}

@override

public void run() {

while (!wake) {

system.out.println("child:i am sleeping...");

try {

thread.sleep(1000);

} catch (interruptedexception e) {

e.printstacktrace();

}

if (r.nextint(10) > 8) {

wakeup();

}

}

}

public void wakeup() {

wake = true;

d.feed(this);

}

public boolean iswake() {

return wake;

}

}

class dad {

public void feed(child c) {

system.out.println("feed child!");

}

}

public class firstquestion {

public static void main(string[] args) {

new thread(new child(new dad())).start();

}

}

这样基本已经实现功能,稍微完善下,假如想知道小孩什么时候起来等一些信息,如果我们写在小孩类中就不太合适,所以我们抽象出类中wakenupevent:

class wakenupevent {

private date date;

private string loc;

private dad dad;

public wakenupevent(date date, string loc, dad dad) {

super();

this.date = date;

this.loc = loc;

this.dad = dad;

}

}

class child implements runnable {

private dad d;

public child(dad d) {

this.d = d;

}

@override

public void run() {

try {

thread.sleep(5000);

} catch (interruptedexception e) {

e.printstacktrace();

}

wakeup();

}

public void wakeup() {

d.actiontowakenup(new wakenupevent(new date(), "child", d));

}

}

class dad {

public void actiontowakenup(wakenupevent wakenupevent) {

system.out.println("child feed!");

}

}

public class firstquestion {

public static void main(string[] args) {

new thread(new child(new dad())).start();

}

}

这样dad可以做自己事,只要听到孩子声音,就过来喂奶。似乎问题已经解决,假如小孩醒后,小孩的爷爷想抱下,小孩家的小狗要叫下,等等,如果按照上面的设计,小孩需要持有爷爷grandfather、狗dog等的引用,再调用用响应的处理方法…需要修改较大的篇幅。实际上我们可以在小孩中使用一个集合存储所有监听小孩的对象,当小孩醒后,小孩依次调用监听者处理方法。要实现统一的接口,以可以被小孩监听器集合引用和调用相应方法,我们使用接口interface。

class wakenupevent {

private date date;

private string eventtype;

private object source;

public wakenupevent(date date, string eventtype, object source) {

this.date = date;

this.eventtype = eventtype;

this.source = source;

}

}

class child implements runnable {

private list list = new arraylist();

public void addwakenuplistener(wakenuplistener l) {

list.add(l);

}

@override

public void run() {

system.out.println("child is sleeping...");

try {

thread.sleep(2000);

} catch (interruptedexception e) {

e.printstacktrace();

}

wakeup();

}

public void wakeup() {

for (wakenuplistener l : list) {

l.actionwakenup(new wakenupevent(new date(), "", this));

}

}

}

interface wakenuplistener {

void actionwakenup(wakenupevent e);

}

class dad implements wakenuplistener {

@override

public void actionwakenup(wakenupevent e) {

system.out.println("dad feed child!");

}

}

class grandfather implements wakenuplistener {

@override

public void actionwakenup(wakenupevent e) {

system.out.println("grandfather holl child!");

}

}

public class firstquestion {

public static void main(string[] args) {

child c = new child();

c.addwakenuplistener(new dad());

c.addwakenuplistener(new grandfather());

new thread(c).start();

}

}

这个时候再看概述的例子,比较容易理解了吧!

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[gof 《设计模式》]

观察者模式中的推模式与拉模式[摘录]

在observer模式中区分推模式和拉模式,先简单的解释一下两者的区别:推模式是当有消息时,把消息信息以参数的形式传递(推)给所有观察者,而拉模式是当有消息时,通知消息的方法本身并不带任何的参数,是由观察者自己到主体对象那儿取回(拉)消息。知道了这一点,大家可能很容易发现上面我所举的例子其实是一种推模式的observer模式。我们先看看这种模式带来了什么好处:当有消息时,所有的观察者都会直接得到全部的消息,并进行相应的处理程序,与主体对象没什么关系,两者之间的关系是一种松散耦合。但是它也有缺陷,第一是所有的观察者得到的消息是一样的,也许有些信息对某个观察者来说根本就用不上,也就是观察者不能“按需所取”;第二,当通知消息的参数有变化时,所有的观察者对象都要变化。鉴于以上问题,拉模式就应运而生了,它是由观察者自己主动去取消息,需要什么信息,就可以取什么,不会像推模式那样得到所有的消息参数。ok,说到这儿,你是否对于推模式和拉模式有了一点了解呢?

实际上上面的代码中,因java中awt事件的影响,我在event中加入了source字段,这算是拉模式的一种体现。我们可以得到公共的事件信息,也可以通过source得到发出事件对象的信息。

awt事件模拟

说到awt事件,我们根据上面的思路模拟下awt事件处理,观察者模式实现awt事件功能更加简单优雅,然而真正的awt也需要windows本身的事件驱动的支持,比如你按下某个button,首先windows捕获这个消息,把消息分发给java虚拟机,虚拟机在调用button相应的处理,button调用监听器处理(个人理解)。一般awt事件处理:

public class awtbutton extends frame {

public void lanch() {

button b = new button("test");

b.addactionlistener(new myactionlistener());

b.addactionlistener(new myactionlistener1());

this.add(b);

this.addwindowlistener(new windowadapter() {

@override

public void windowclosing(windowevent e) {

system.exit(0);

}

});

setsize(100, 100);

setvisible(true);

}

public static void main(string[] args) {

new awtbutton().lanch();

}

class myactionlistener implements actionlistener {

@override

public void actionperformed(actionevent e) {

system.out.println("button pressed!");

}

}

class myactionlistener1 implements actionlistener {

@override

public void actionperformed(actionevent e) {

system.out.println("button pressed1!");

}

}

}

结合上面的孩子的例子,我们使用控制台模拟awt事件:

public class simulationawtbutton {

public static void main(string[] args) {

button b = new button();

b.addactionlistener(new myactionlistener1());

b.addactionlistener(new myactionlistener2());

b.pressed();

}

}

class button {

private list.net设计模式(19):观察者模式(observer pattern)(部分摘录原文)

java尚学堂马士兵设计模式

百度百科:观察者模式

作者:syxchina

出处:http://syxchina.cnblogs.com

http://hi.baidu.com/syxcs123

本文版权归作者、博客园和百度空间共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则作者会诅咒你的。

标签: 设计模式, design pattern

绿色通道:好文要顶关注我收藏该文与我联系


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值