21.观察者模式(Observer)
每个月当银行发放工资时,都会有短信自动通知员工,员工就相当于观察者,账户就是被观察者,当账户余额有变动时,会自动通知观察者,这就是观察者模式的实际应用。
哪里会使用到观察者模式
比如银行的手机提醒功能,当账户余额变动时,只要将手机号注册到银行系统中,就会自动通知到手机上。
目前网上商城比较流行,当有新的货物或货物价格有变化时,只要将电子邮件注册到网站上,就可以自动收到新货物或价格变动的邮件。
观察者模式的实现原理
观察者模式在银行系统的应用
其实JAVA本身已经实现了观察者模式,通过JAVA中的Observer接口和Observable类就可以实现观察者模式。其中被观察者继承Observable类,观察者实现Observer接口。
CustomerBank1
package observer.app1;
import java.util.Observable;
import java.util.Observer;
public class CustomerBank1 implements Observer {
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public void update(Observable obj, Object arg) {
double amt = Double.parseDouble(arg.toString());
System.out.println("账户金额发生变动,发送邮件到" + email + ",变动后金额为:" + amt);
}
}
CustomerBank2
package observer.app1;
import java.util.Observable;
import java.util.Observer;
public class CustomerBank2 implements Observer {
private String phone;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public void update(Observable obj, Object arg) {
double amt = Double.parseDouble(arg.toString());
System.out.println("账户金额发生变动,发送短信到" + phone + ",变动后金额为:" + amt);
}
}
CustomerBank3
package observer.app1;
import java.util.Observable;
import java.util.Observer;
public class CustomerBank3 implements Observer {
private String qq;
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
@Override
public void update(Observable obj, Object arg) {
double amt = Double.parseDouble(arg.toString());
System.out.println("账户金额发生变动,发送信息到" + qq + ",变动后金额为:" + amt);
}
}
BankObserver
package observer.app1;
public interface BankObserver {
public void update(double amt);
}
BankAccount
package observer.app1;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
public class BankAccount extends Observable {
private String name;
private double amt;
List<BankObserver> list = new ArrayList<BankObserver>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getAmt() {
return amt;
}
// 添加观察者
public void add(BankObserver bankObserver) {
list.add(bankObserver);
}
// 删除观察者
public void remove(BankObserver bankObserver) {
list.remove(bankObserver);
}
// 通知金额改变
public void notifyAmt() {
for (int i = 0; i < list.size(); i++) {
BankObserver bankObserver = (BankObserver) list.get(i);
bankObserver.update(amt);
}
}
public void setAmt(double amt) {
this.amt = amt;
// notifyAmt();
setChanged();
notifyObservers(amt);
}
}
Client
package observer.app1;
public class Client {
public static void main(String[] argv) {
BankAccount bankAccount = new BankAccount();
CustomerBank1 customerBank1 = new CustomerBank1();
customerBank1.setEmail("****@***.com");
CustomerBank2 customerBank2 = new CustomerBank2();
customerBank2.setPhone("123456789");
CustomerBank3 customerBank3 = new CustomerBank3();
customerBank3.setQq("000000000");
bankAccount.addObserver(customerBank1);
bankAccount.addObserver(customerBank2);
bankAccount.addObserver(customerBank3);
bankAccount.setAmt(1000);
}
}
观察者模式在网上商城的应用
观察者模式在Spring中的实现
在Spring中,任何一个类要能够称为事件源,首先得继承ApplicationContentextAware并在响应的方法中产生事件对象,并通过publishEvent方法对事件进行传播,另外监听器必须实现ApplicationListener接口。
ApplicationListener是观察者接口。
ApplicationListener
package org.springframework.context;
import java.util.EventListener;
public abstract interface ApplicationListener<E extends ApplicationEvent>
extends EventListener
{
public abstract void onApplicationEvent(E paramE);
}
ApplicationEvent
package org.springframework.context;
import java.util.EventObject;
public abstract class ApplicationEvent
extends EventObject
{
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source)
{
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp()
{
return this.timestamp;
}
}
ApplicationContextAware
package org.springframework.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
public abstract interface ApplicationContextAware
extends Aware
{
public abstract void setApplicationContext(ApplicationContext paramApplicationContext)
throws BeansException;
}
AbstractApplicationEventMulticaster是被观察者,在AbstractApplicationEventMulticaster中定义了一个applicationListeners,在子类SimpleApplicationEventMulticaster通过遍历applicationListeners来执行各个listener中的onApplicationEvent。
AbstractApplicationEventMulticaster
package org.springframework.context.event;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.OrderComparator;
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanFactoryAware
{
private final ListenerRetriever defaultRetriever;
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache;
private BeanFactory beanFactory;
public AbstractApplicationEventMulticaster()
{
this.defaultRetriever = new ListenerRetriever(false);
this.retrieverCache = new ConcurrentHashMap(64);
}
public void addApplicationListener(ApplicationListener listener)
{
synchronized (this.defaultRetriever)
{
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
public void addApplicationListenerBean(String listenerBeanName)
{
synchronized (this.defaultRetriever)
{
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
public void removeApplicationListener(ApplicationListener listener)
{
synchronized (this.defaultRetriever)
{
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
public void removeApplicationListenerBean(String listenerBeanName)
{
synchronized (this.defaultRetriever)
{
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
this.retrieverCache.clear();
}
}
public void removeAllListeners()
{
synchronized (this.defaultRetriever)
{
this.defaultRetriever.applicationListeners.clear();
this.defaultRetriever.applicationListenerBeans.clear();
this.retrieverCache.clear();
}
}
public final void setBeanFactory(BeanFactory beanFactory)
{
this.beanFactory = beanFactory;
}
private BeanFactory getBeanFactory()
{
if (this.beanFactory == null) {
throw new IllegalStateException("ApplicationEventMulticaster cannot retrieve listener beans because it is not associated with a BeanFactory");
}
return this.beanFactory;
}
protected Collection<ApplicationListener> getApplicationListeners()
{
synchronized (this.defaultRetriever)
{
return this.defaultRetriever.getApplicationListeners();
}
}
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event)
{
Class<? extends ApplicationEvent> eventType = event.getClass();
Class sourceType = event.getSource().getClass();
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
ListenerRetriever retriever = (ListenerRetriever)this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
LinkedList<ApplicationListener> allListeners = new LinkedList();
Set<ApplicationListener> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever)
{
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener listener : listeners) {
if (supportsEvent(listener, eventType, sourceType))
{
retriever.applicationListeners.add(listener);
allListeners.add(listener);
}
}
BeanFactory beanFactory;
if (!listenerBeans.isEmpty())
{
beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans)
{
ApplicationListener listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if ((!allListeners.contains(listener)) && (supportsEvent(listener, eventType, sourceType)))
{
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
return allListeners;
}
protected boolean supportsEvent(ApplicationListener listener, Class<? extends ApplicationEvent> eventType, Class sourceType)
{
SmartApplicationListener smartListener = (listener instanceof SmartApplicationListener) ? (SmartApplicationListener)listener : new GenericApplicationListenerAdapter(listener);
return (smartListener.supportsEventType(eventType)) && (smartListener.supportsSourceType(sourceType));
}
private static class ListenerCacheKey
{
private final Class eventType;
private final Class sourceType;
public ListenerCacheKey(Class eventType, Class sourceType)
{
this.eventType = eventType;
this.sourceType = sourceType;
}
public boolean equals(Object other)
{
if (this == other) {
return true;
}
ListenerCacheKey otherKey = (ListenerCacheKey)other;
return (this.eventType.equals(otherKey.eventType)) && (this.sourceType.equals(otherKey.sourceType));
}
public int hashCode()
{
return this.eventType.hashCode() * 29 + this.sourceType.hashCode();
}
}
private class ListenerRetriever
{
public final Set<ApplicationListener> applicationListeners;
public final Set<String> applicationListenerBeans;
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered)
{
this.applicationListeners = new LinkedHashSet();
this.applicationListenerBeans = new LinkedHashSet();
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener> getApplicationListeners()
{
LinkedList<ApplicationListener> allListeners = new LinkedList();
for (ApplicationListener listener : this.applicationListeners) {
allListeners.add(listener);
}
BeanFactory beanFactory;
if (!this.applicationListenerBeans.isEmpty())
{
beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans)
{
ApplicationListener listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if ((this.preFiltered) || (!allListeners.contains(listener))) {
allListeners.add(listener);
}
}
}
OrderComparator.sort(allListeners);
return allListeners;
}
}
}
SimpleApplicationEventMulticaster
package org.springframework.context.event;
import java.util.concurrent.Executor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class SimpleApplicationEventMulticaster
extends AbstractApplicationEventMulticaster
{
private Executor taskExecutor;
public SimpleApplicationEventMulticaster() {}
public SimpleApplicationEventMulticaster(BeanFactory beanFactory)
{
setBeanFactory(beanFactory);
}
public void setTaskExecutor(Executor taskExecutor)
{
this.taskExecutor = taskExecutor;
}
protected Executor getTaskExecutor()
{
return this.taskExecutor;
}
public void multicastEvent(final ApplicationEvent event)
{
for (final ApplicationListener listener : getApplicationListeners(event))
{
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable()
{
public void run()
{
listener.onApplicationEvent(event);
}
});
} else {
listener.onApplicationEvent(event);
}
}
}
}
22.命令模式(Command)
哪里会使用到命令模式
到银行办理业务时,通常要先到取号机进行取号,然后到相应的窗口办理业务,这里的取号机就是下达具体某个窗口执行指令的命令类。
再比如全自动洗衣机,可以自行设定洗涤时间,到时间洗衣机就能自动洗涤、漂洗,只需要选择相应的指令即可。
命令模式的实现原理
命令模式在Struts中的实际应用
Struts2的Action类可以实现一个Action接口,也可以实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现常用的接口,但Action接口不是必需的,任何有execute标识的POJO对象都可以用做Struts2的Action对象。
23.备忘录模式(Memento)
在软件构建过程中,某些对象的状态在转换过程中,可能由于某些需要,要求程序能够回溯到对象之前处于某个点时的状态
哪里会使用到备忘录模式
在企业交往过程中,经常会看到某某企业双方签署了备忘录,以供以后进行查询。软件开发中,如人力资源系统,在录入当前人资料时,突然发现前一个人的资料录入错误,此时就需要将前面一个人的资料恢复过来,然后进行修改,此时就需要使用备忘录模式。
在使用word编辑文档时,经常会遇到电脑死机或停电的情况,此时,如果重新打开word,就会发现word已经记录了在停电前正在编辑的文档,并且会询问用户是否需要恢复到以前的文档。
在网站应用中,经常会用到数据的备份和恢复,每天进行一次增量备份,每周进行一次全面备份,以保证数据的完整和安全性,一边必要时进行数据恢复。
备忘录模式的实现原理
备忘录模式就是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态。使用备忘录模式,可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息,而且能够在对象需要时恢复到先前的状态。
Memento
package memento.app1;
public class Memento {
public Memento(People people) {
this.name = people.getName();
this.sex = people.getSex();
this.age = people.getAge();
}
private String name;
private String sex;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
People
package memento.app1;
public class People {
private String name;
private String sex;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
// 备忘者
public Memento getMemento() {
return new Memento(this);
}
// 获取备忘的内容
public void setMemento(Memento memento) {
this.name = memento.getName();
this.sex = memento.getSex();
this.age = memento.getAge();
}
}
Client
package memento.app1;
public class Client {
public static void main(String[] argv) {
People people = new People();
people.setName("张三");
people.setAge("18岁");
people.setSex("男");
System.out.println("第一次创建的对象:" + "姓名:" + people.getName() + ",年龄:"
+ people.getAge() + ",性别:" + people.getSex());
Memento memento = people.getMemento();
people.setName("王五");
people.setAge("28岁");
people.setSex("女");
System.out.println("第二次创建的对象:" + "姓名:" + people.getName() + ",年龄:"
+ people.getAge() + ",性别:" + people.getSex());
people.setMemento(memento);
System.out.println("恢复成第一次创建的对象:" + "姓名:" + people.getName() + ",年龄:"
+ people.getAge() + ",性别:" + people.getSex());
}
}