前言
设计模式是解决问题的方案,从大神的代码中学习对设计模式的使用,可以有效提升个人编码及设计代码的能力,下面看一下几个主要的设计模式:策略模式、模板方法模式、迭代器模式、观察者模式 及 责任链模式
一、策略模式
定义一系列算法,封装每个算法 并使它们可以互换。该模式的主要角色如下:
Strategy 接口:用于定义一个算法族,它们都具有 behavior()方法;
Context:使用该算法的类,持有 Strategy 对象,其中的 setStrategy(Strategy stra)方法可以动态地改变 strategy 对象,以此改变自己所使用的算法。
mybatis中的实现:
mybatis 的 DefaultSqlSession 使用了策略模式,DefaultSqlSession 扮演了 Context 的角色,Executor 接口及其实现类扮演了策略接口及实现。DefaultSqlSession 持有 Executor 对象,在 DefaultSqlSession 实例化时通过构造方法传入具体的 Executor 对象,根据持有的 Executor 对象的不同,而使用不同的策略进行数据库操作。具体使用哪个 Executor 的实例,由 Configuration 的 newExecutor() 方法决定。
public class DefaultSqlSession implements SqlSession {
private final Executor executor;
/**
* 在构造方法中为 executor 赋值,没有提供专门的set方法
*/
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
/**
* executor的不同,决定了DefaultSqlSession使用哪种策略执行SQL操作
*/
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
public interface Executor {
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
void commit(boolean required) throws SQLException;
void rollback(boolean required) throws SQLException;
Transaction getTransaction();
......
}
public abstract class BaseExecutor implements Executor {
......
protected BaseExecutor(Configuration configuration, Transaction transaction) {
this.transaction = transaction;
this.deferredLoads = new ConcurrentLinkedQueue<>();
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
this.closed = false;
this.configuration = configuration;
this.wrapper = this;
}
......
}
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 获取配置对象
Configuration configuration = ms.getConfiguration();
// 创建 StatementHandler 对象,实际返回的是 RoutingStatementHandler 对象,前面介绍过,
// 其中根据 MappedStatement.statementType 选择具体的 StatementHandler 实现
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 完成 Statement 的创建和初始化,该方法首先会调用 StatementHandler.prepare() 方法
// 创建 Statement 对象, 然后调用 StatementHandler. parameterize() 方法处理占位符
stmt = prepareStatement(handler, ms.getStatementLog());
// 调用 StatementHandler.query() 方法,执行 SQL 语句,并通过 ResultSetHandler 完成
// 结果集的映射
return handler.query(stmt, resultHandler);
} finally {
// 关闭 Statement 对象
closeStatement(stmt);
}
}
......
}
public class BatchExecutor extends BaseExecutor {
@Override
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
// 获取配置对象
final Configuration configuration = ms.getConfiguration();
// 创建 StatementHandler 对象
final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
final BoundSql boundSql = handler.getBoundSql();
// 获取 SQL 语句
final String sql = boundSql.getSql();
final Statement stmt;
// 如果当前执行的 SQL 模式与上次执行的 SQL 模式相同且对应的 MappedStatement 对象相同
if (sql.equals(currentSql) && ms.equals(currentStatement)) {
// 获取 statementList 集合中最后一个 Statement 对象
int last = statementList.size() - 1;
stmt = statementList.get(last);
applyTransactionTimeout(stmt);
// 绑定实参,处理占位符 “?”
handler.parameterize(stmt);//fix Issues 322
// 查找对应的 BatchResult 对象,并记录用户传入的实参
BatchResult batchResult = batchResultList.get(last);
batchResult.addParameterObject(parameterObject);
} else {
Connection connection = getConnection(ms.getStatementLog());
// 创建新的 Statement 对象
stmt = handler.prepare(connection, transaction.getTimeout());
// 绑定实参,处理占位符“?”
handler.parameterize(stmt); //fix Issues 322
// 更新 currentSql 和 currentStatement
currentSql = sql;
currentStatement = ms;
// 将新创建的 Statement 对象添加到 statementList 集合中
statementList.add(stmt);
// 添加新的 BatchResult 对象
batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
// 底层通过调用 Statement.addBatch() 方法添加 SQL 语句
handler.batch(stmt);
return BATCH_UPDATE_RETURN_VALUE;
}
......
}
public class Configuration {
/**
* 在这个方法中决定使用哪个 Executor 实现
*/
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
......
}
二、模板方法模式
在该模式中,一个算法可以分为多个步骤,这些步骤的执行次序在一个被称为“模板方法”的方法中定义,而算法的每个步骤都对应着一个方法,这些方法被称为 “基本方法”。 模板方法按照它定义的顺序依次调用多个基本方法,从而实现整个算法流程。在模板方法模式中,会将模板方法的实现以及那些固定不变的基本方法的实现放在父类中,而那些不固定的基 本方法在父类中只是抽象方法,其真正的实现代码会被延迟到子类中完成。
Spring 中的应用
Spring 中的 AbstractApplicationContext 和其子类 AbstractRefreshableApplicationContext、GenericApplicationContext 使用了模板方法模式。源码实现及详细注释如下。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
/**
* 告诉子类启动refreshBeanFactory()方法,BeanDefinition资源文件的载入
* 从子类的refreshBeanFactory()方法启动开始
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 这里使用了模板方法模式,自己定义了流程,个性化的方法实现交由子类完成
// 其中,refreshBeanFactory() 和 getBeanFactory()为抽象方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
/**
* 在这里完成了容器的初始化,并赋值给自己private的beanFactory属性,为下一步调用做准备
* 从父类AbstractApplicationContext继承的抽象方法,自己做了实现
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果已经建立了IoC容器,则销毁并关闭容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建IoC容器,DefaultListableBeanFactory类实现了ConfigurableListableBeanFactory接口
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 定制化IoC容器,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);
// 载入BeanDefinition,这里又使用了一个委派模式,在当前类定义此抽象方法,子类容器具体实现
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
// 给自己的属性赋值
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call 'refresh' before accessing beans via the ApplicationContext");
}
return this.beanFactory;
}
}
}
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (this.refreshed) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
this.refreshed = true;
}
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
}
## Mybatis 中的应用
mybatis 的 Executor 组件使用了该模式,其中抽象类 BaseExecutor 定义了模板方法和抽象方法,实现类 SimpleExecutor、BatchExecutor 及 ReuseExecutor 对抽象方法进行具体实现。源码如下。
public abstract class BaseExecutor implements Executor {
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
// 判断当前 Executor 是否已经关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// clearLocalCache() 方法中会调用 localCache()、localOutputParameterCache() 两个
// 缓存的 clear() 方法完成清理工作。这是影响一级缓存中数据存活时长的第三个方面
clearLocalCache();
// 调用 doUpdate() 抽象方法执行 SQL 语句
return doUpdate(ms, parameter);
}
public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
// 判断当前 Executor 是否已经关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 调用抽象方法 doFlushStatements(),其参数 isRollBack 表示是否执行 Executor 中缓存的
// SQL 语句,false 表示执行,true 表示不执行
return doFlushStatements(isRollBack);
}
/**
* 调用 doQuery() 方法完成数据库查询,并得到映射后的结果集对象,
*/
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
// 在缓存中添加占位符
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 调用 doQuery() 抽象方法,完成数据库查询操作,并返回结果集对象
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
// 删除占位符
localCache.removeObject(key);
}
// 将真正的结采对象添加到一级缓存中
localCache.putObject(key, list);
// 是否为存储过程调用
if (ms.getStatementType() == StatementType.CALLABLE) {
// 缓存输出类型的参数
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
@Override
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
return doQueryCursor(ms, parameter, rowBounds, boundSql);
}
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
throws SQLException;
}
public class SimpleExecutor extends BaseExecutor {
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 获取配置对象
Configuration configuration = ms.getConfiguration();
// 创建 StatementHandler 对象,实际返回的是 RoutingStatementHandler 对象,前面介绍过,
// 其中根据 MappedStatement.statementType 选择具体的 StatementHandler 实现
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 完成 Statement 的创建和初始化,该方法首先会调用 StatementHandler.prepare() 方法
// 创建 Statement 对象, 然后调用 StatementHandler. parameterize() 方法处理占位符
stmt = prepareStatement(handler, ms.getStatementLog());
// 调用 StatementHandler.query() 方法,执行 SQL 语句,并通过 ResultSetHandler 完成
// 结果集的映射
return handler.query(stmt, resultHandler);
} finally {
// 关闭 Statement 对象
closeStatement(stmt);
}
}
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
Cursor<E> cursor = handler.queryCursor(stmt);
stmt.closeOnCompletion();
return cursor;
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
return Collections.emptyList();
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
}
public class BatchExecutor extends BaseExecutor {
@Override
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
// 获取配置对象
final Configuration configuration = ms.getConfiguration();
// 创建 StatementHandler 对象
final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
final BoundSql boundSql = handler.getBoundSql();
// 获取 SQL 语句
final String sql = boundSql.getSql();
final Statement stmt;
// 如果当前执行的 SQL 模式与上次执行的 SQL 模式相同且对应的 MappedStatement 对象相同
if (sql.equals(currentSql) && ms.equals(currentStatement)) {
// 获取 statementList 集合中最后一个 Statement 对象
int last = statementList.size() - 1;
stmt = statementList.get(last);
applyTransactionTimeout(stmt);
// 绑定实参,处理占位符 “?”
handler.parameterize(stmt);//fix Issues 322
// 查找对应的 BatchResult 对象,并记录用户传入的实参
BatchResult batchResult = batchResultList.get(last);
batchResult.addParameterObject(parameterObject);
} else {
Connection connection = getConnection(ms.getStatementLog());
// 创建新的 Statement 对象
stmt = handler.prepare(connection, transaction.getTimeout());
// 绑定实参,处理占位符“?”
handler.parameterize(stmt); //fix Issues 322
// 更新 currentSql 和 currentStatement
currentSql = sql;
currentStatement = ms;
// 将新创建的 Statement 对象添加到 statementList 集合中
statementList.add(stmt);
// 添加新的 BatchResult 对象
batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
// 底层通过调用 Statement.addBatch() 方法添加 SQL 语句
handler.batch(stmt);
return BATCH_UPDATE_RETURN_VALUE;
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
flushStatements();
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
Connection connection = getConnection(ms.getStatementLog());
Statement stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
Cursor<E> cursor = handler.queryCursor(stmt);
stmt.closeOnCompletion();
return cursor;
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
// results 集合用于储存批处理的结采
List<BatchResult> results = new ArrayList<>();
// 如果明确指定了要回滚事务,则直接返回空集合,忽略 statementList 集合中记录的 SQL 语句
if (isRollback) {
return Collections.emptyList();
}
// 遍历 statementList 集合
for (int i = 0, n = statementList.size(); i < n; i++) {
// 获取 Statement 对象
Statement stmt = statementList.get(i);
applyTransactionTimeout(stmt);
// 获取对应 BatchResult 对象
BatchResult batchResult = batchResultList.get(i);
try {
// 调用 Statement.executeBatch() 方法批量执行其中记录的 SQL 语句,并使用返回的 int 数组
// 更新 BatchResult.updateCounts 字段,其中每一个元素都表示一条 SQL 语句影响的记录条数
batchResult.setUpdateCounts(stmt.executeBatch());
MappedStatement ms = batchResult.getMappedStatement();
List<Object> parameterObjects = batchResult.getParameterObjects();
// 获取配置的 KeyGenerator 对象
KeyGenerator keyGenerator = ms.getKeyGenerator();
if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
// 获取数据库生成的主键,并设置到 parameterObjects 中,前面已经分析过,这里不再重复
jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
} else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
// 对于其他类型的 KeyGenerator,会调用其 processAfter() 方法
for (Object parameter : parameterObjects) {
keyGenerator.processAfter(this, ms, stmt, parameter);
}
}
// Close statement to close cursor #1109
closeStatement(stmt);
} catch (BatchUpdateException e) {
StringBuilder message = new StringBuilder();
message.append(batchResult.getMappedStatement().getId())
.append(" (batch index #")
.append(i + 1)
.append(")")
.append(" failed.");
if (i > 0) {
message.append(" ")
.append(i)
.append(" prior sub executor(s) completed successfully, but will be rolled back.");
}
throw new BatchExecutorException(message.toString(), e, results, batchResult);
}
// 添加 BatchResult 到 results 集合
results.add(batchResult);
}
return results;
} finally {
// 关闭所有 Statement 对象,并清空 currentSql 字段、清空 statementList 集合、
// 清空 batchResultList 集合(略)
for (Statement stmt : statementList) {
closeStatement(stmt);
}
currentSql = null;
statementList.clear();
batchResultList.clear();
}
}
}
public class ReuseExecutor extends BaseExecutor {
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
}
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.queryCursor(stmt);
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
statementMap.clear();
return Collections.emptyList();
}
}
三.观察者模式
该模式用于定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知,然后自动更新。类图和主要角色如下:
Subject 主题:具有注册、移除及通知观察者的功能,主题是通过维护一个观察者列表来实现这些功能的;
Observer 观察者:其注册需要 Subject 的 registerObserver()方法。
JDK 中的源码实现
/**
* 当一个类希望获知 所观察的对象的变化时,可以通过实现本接口来完成
* 而被观察的对象则需要继承 Observable 类
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
public interface Observer {
/**
* 每当所观察的对象发生更改时,此方法都会被调用。应用程序调用Observable对象的
* notifyObservators()方法时,将通知所有注册的观察者 本对象(被观察者)已更新
*/
void update(Observable o, Object arg);
}
/**
* 这个类表示一个可被观察的对象,或者模型视图范例中的“数据”。它可以被继承,
* 以表示该类 可以被观察到。
* 一个Observable对象可以有一个或多个观察者,观察者可以是实现了Observer接口的任何对象。
* 在一个Observable实例更改之后,调用其notifyObservers()方法,该方法可以通过调用 所有
* 已注册的Observer对象的update()方法通知其所有观察者,被观察的对象已更新。
* @author Chris Warth
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
* @see java.util.Observer
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
* @since JDK1.0
*/
public class Observable {
private boolean changed = false;
/**
* 通过一个Vector来维护 观察者列表。
* 由于该集合主要涉及元素的增删操作,所以个人认为使用LinkedList
* 效果会更好一下
*/
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
/**
* 注册 观察者对象
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* 移除观察者对象
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
/**
* 如果此对象已更改,则通知其所有观察者,然后调用clearChanged()方法 清除更改标记
*/
public void notifyObservers(Object arg) {
// 一个临时数组缓冲区,用作当前观察者状态的快照
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* 清除观察者列表,使此对象不再具有任何观察者
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
* 将本对象标记为已更改
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* 清除本对象的更改标准
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* 查看本对象是否已更改
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* 返回观察者列表的长度
*/
public synchronized int countObservers() {
return obs.size();
}
}