目录
1、JDK设计模式
1.1 单例模式
java.lang.SecurityManager
java.lang.Runtime
1.2 装饰者模式
public static void main(String[] args) throws IOException {
DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream("data.txt")));//关键点
System.out.println(dis.readByte());
System.out.println(dis.readInt());
System.out.println(dis.readChar());
System.out.println(dis.readFloat());
dis.close();
}
DataInputStream、BufferedInputStream都继承自FilterInputStream,而FilterInputStream是InputStream的一个装饰者,源码如下:
package java.io;
/**
* A <code>FilterInputStream</code> contains
* some other input stream, which it uses as
* its basic source of data, possibly transforming
* the data along the way or providing additional
* functionality. The class <code>FilterInputStream</code>
* itself simply overrides all methods of
* <code>InputStream</code> with versions that
* pass all requests to the contained input
* stream. Subclasses of <code>FilterInputStream</code>
* may further override some of these methods
* and may also provide additional methods
* and fields.
*
* @author Jonathan Payne
* @since JDK1.0
*/
public
class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
protected FilterInputStream(InputStream in) {
this.in = in;
}
//这里删除无关代码........
}
1.3 观察者模式
java.util.EventObject、java.util.Observer、java.util.EventListener是JDK中观察者模式的提现,提供了基础的事件对象与观察者对象,java.awt包、java.swing包中大量的事件、监听者都继承自这两个类,从而实现了事件模型。
1.4 简单工厂方法模式
java.util.Calendar使用了工厂模式的简单工厂模式
/**
* Gets a calendar with the specified time zone and locale.
* The <code>Calendar</code> returned is based on the current time
* in the given time zone with the given locale.
*
* @param zone the time zone to use
* @param aLocale the locale for the week data
* @return a Calendar.
*/
public static Calendar getInstance(TimeZone zone,
Locale aLocale)
{
return createCalendar(zone, aLocale);
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
线程池中的TheadFactory使用到了工厂方法模式,源码如下:
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
package java.util.concurrent;
/**
* An object that creates new threads on demand. Using thread factories
* removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
* enabling applications to use special thread subclasses, priorities, etc.
*
* <p>
* The simplest implementation of this interface is just:
* <pre> {@code
* class SimpleThreadFactory implements ThreadFactory {
* public Thread newThread(Runnable r) {
* return new Thread(r);
* }
* }}</pre>
*
* The {@link Executors#defaultThreadFactory} method provides a more
* useful simple implementation, that sets the created thread context
* to known values before returning it.
* @since 1.5
* @author Doug Lea
*/
public interface ThreadFactory {
/**
* Constructs a new {@code Thread}. Implementations may also initialize
* priority, name, daemon status, {@code ThreadGroup}, etc.
*
* @param r a runnable to be executed by new thread instance
* @return constructed thread, or {@code null} if the request to
* create a thread is rejected
*/
Thread newThread(Runnable r);
}
1.5 策略模式
线程池中的RejectedExecutionHandler使用到了策略模式,如下:
1.6 迭代器模式
java.util.Collection.iterator()使用了迭代器模式
/**
* Returns an iterator over the elements in this collection. There are no
* guarantees concerning the order in which the elements are returned
* (unless this collection is an instance of some class that provides a
* guarantee).
*
* @return an <tt>Iterator</tt> over the elements in this collection
*/
Iterator<E> iterator();
1.7 享元模式
1、java.lang.Integer中valueOf(int i) 方法使用了享元模式:
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
- java.lang.Integer#valueOf(int)
- java.lang.Boolean#valueOf(boolean)
- java.lang.Byte#valueOf(byte)
- java.lang.Character#valueOf(char)
2、线程池是享元模式的一个很好的应用
1.8 原型模式
java.lang.Cloneable是一个Tag接口:
* Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
package java.lang;
/**
* A class implements the <code>Cloneable</code> interface to
* indicate to the {@link java.lang.Object#clone()} method that it
* is legal for that method to make a
* field-for-field copy of instances of that class.
* <p>
* Invoking Object's clone method on an instance that does not implement the
* <code>Cloneable</code> interface results in the exception
* <code>CloneNotSupportedException</code> being thrown.
* <p>
* By convention, classes that implement this interface should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* <p>
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
*
* @author unascribed
* @see java.lang.CloneNotSupportedException
* @see java.lang.Object#clone()
* @since JDK1.0
*/
public interface Cloneable {
}
调用java.lang.Object中的clone()方法,实际是原型模式的一个体现,利用已经存在的对象快速的创建一个新对象,Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
1.9 模板方法模式
java.util.AbstractList中的 public boolean addAll(int index, Collection<? extends E> c)方法:
/**
* {@inheritDoc}
*
* <p>This implementation gets an iterator over the specified collection
* and iterates over it, inserting the elements obtained from the
* iterator into this list at the appropriate position, one at a time,
* using {@code add(int, E)}.
* Many implementations will override this method for efficiency.
*
* <p>Note that this implementation throws an
* {@code UnsupportedOperationException} unless
* {@link #add(int, Object) add(int, E)} is overridden.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);//由子类ArrayList、LinkedList进行实现
boolean modified = false;
for (E e : c) {
add(index++, e);//由子类ArrayList、LinkedList进行实现
modified = true;
}
return modified;
}
1.10 命令模式
JDK 中的 Runnable 接口是命令模式的一个体现,命令的发出者是主调线程,而命令的执行者是线程池中的线程,命令的发现与执行不是同一个对象,解耦了命令的请求者与执行者。
1.11 代理模式
1、Proxy实现的动态代理
public static void main(String[] args) {
Subject subject=new SubjectImpl();
Subject subjectProxy=(Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new ProxyInvocationHandler(subject));
subjectProxy.sayHi();
subjectProxy.sayHello();
}
2、RMI
1.12 建造者模式
StringBuilder.toString()方法
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
1.13 外观模式
外观模式在JDK源码中不容易找,但是在Tomcat中还是比较容易找到对应示例的。Tomcat中有很多场景都使用到了外观模式,因为Tomcat中有很多不同的组件,每个组件需要相互通信,但又不能将自己内部数据过多地暴露给其他组件。
用外观模式隔离数据是个很好的方法,比如Request上使用外观模式:
因为Request类中很多方法都是组件内部之间交互用的,比如setComet、setReuqestedSessionId等方法,这些方法并不对外公开,但又必须设置为public,因为还要和内部组件交互使用。最好的解决方法就是通过使用一个Facade类,
屏蔽掉内部组件之间交互的方法,只提供外部程序要使用的方法。如果不使用Facade,直接传递的是HttpServletRequest和HttpServletResponse,那么熟悉容器内部运作的开发者可以分别把ServletRequest和ServletResponse向下转型
为HttpServletRequest和HttpServletResponse,这样就有安全性的问题了。
1.14 责任链模式
下面来看一个 JDK 中常见的 Filter 类,源码如下。
public interface Filter {
void init(FilterConfig var1) throws ServletException;
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
void destroy();
}
Filter 接口的定义非常简单,相当于责任链模式中的 Handler 抽象角色,那么它是如何形成一条责任链的呢?可以看到 doFilter() 方法的最后一个参数类型是 FilterChain。下面来看 FilterChain 接口。
FilterChain 是 J2EE 规范定义的一个拦截器接口,源码如下。
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
可以看到,FilterChain 类中只定义了一个 doFilter() 方法,并没有维护一个链里面的下一个对象,那么它们是怎么串联成一个责任链,实现链路传递的呢?
实际上,J2EE 只定义了一个规范,具体处理逻辑是由使用者自己来实现的。下面来看一下 Spring 中实现了 FilterChain 接口的 MockFilterChain 类。
public class MockFilterChain implements FilterChain {
@Nullable
private ServletRequest request;
@Nullable
private ServletResponse response;
private final List<Filter> filters;
@Nullable
private Iterator<Filter> iterator;
...
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
Assert.state(this.request == null, "This FilterChain has already been called!");
if (this.iterator == null) {
this.iterator = this.filters.iterator();
}
if (this.iterator.hasNext()) {
Filter nextFilter = this.iterator.next();
nextFilter.doFilter(request, response, this);
}
this.request = request;
this.response = response;
}
...
}
1.15 适配器模式
Enumeration是java中比较早提供的遍历接口,Iterator是新的遍历接口,后来兼容原来旧的代码,需要使用到适配器
Iterator方法
Enumeration方法
为了兼容旧的的迭代器,现需要一个适配器,来适配旧的Enumeration类
package headfirst.hd.adapter.eg;
import java.util.Enumeration;
import java.util.Iterator;
public class EnumerationAdapter<E> implements Iterator<E> {
Enumeration<E> enumeration;
public EnumerationAdapter(Enumeration<E> enumeration) {
this.enumeration = enumeration;
}
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public E next() {
return enumeration.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
1.16 组合模式
JDK中的AWT与Swing包中大量使用了组件模式,
叶子节点:CheckBox 、Button、
分支节点:Container
抽象节点:Component
1.17 桥接模式
适用场景
1、抽象和具体实现之间增加更多灵活性
使用桥接模式可以避免在这两个之间建立静态的继承关系,而是去建立组合关系。
2、一个类存在两个(或多个)独立变化的维度,且这两个维度需要独立进行扩展
对于桥接模式可以这样理解,桥接就像一座桥,可以用来连接两个不同地方,这两个地方自由发展,中间的贸易是通过一座桥来连接。
3、不希望使用继承,或者是由于多层继承导致系统类的个数剧增
从图中我们能很清楚的看到抽象类和接口之间是通过组合方式来关联,这样关联有什么好处呢?抽象类下面可以自行发展自己的子类,并且接口类也可以自己发展子类。两者之间互不影响。这正是我们上面所说的两个维度独立扩展。不要以为客户端只能调用使用抽象类,而是接口下面的实现类可以放入抽象类的子类中进行操作。大致了解完之后,JDBC中又是怎么实现桥接模式的呢?
我们对Driver接口一定不陌生。如果从桥接模式来看,Driver就是一个接口,下面可以有MySQL的Driver,Oracle的Driver,这些就可以当做实现接口类。那么我们现在来看看MySQL中的Driver类.
Driver和Connection之间是通过DriverManager类进行桥接的,不是像我们上面说的那样用组合关系来进行桥接。
1.18 状态模式
java.util.Iterator 使用了状态模式,
抽象状态对象:java.util.Iterator
具体状态对象:java.util.ArrayList.Itr
1.19 工厂方法模式
抽象工厂:java.util.Collection
抽象产品:Iterator
工厂方法:
/**
* Returns an iterator over the elements in this collection. There are no
* guarantees concerning the order in which the elements are returned
* (unless this collection is an instance of some class that provides a
* guarantee).
*
* @return an <tt>Iterator</tt> over the elements in this collection
*/
Iterator<E> iterator();
具体工厂:ArrayList、LinkedList
ArrayList具体工厂方法实现:
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}
1.20 抽象工厂模式(暂未发现)
有些文章说java.util.Collection实现了抽象工厂模式,我个人认为不是很准确,因为Collection中只有一个产品等级结构:Iterator,是工厂方法模式,目前在JDK中不是很好找这个案例,等以后,我发现了
再更新这里
1.21 中介者模式
java.util.Timer使用到了中介者模式,Timer是一个中介者模式,它管理着两个Colleague对象(TaskQueue、TimeThread),客户端通过与Timer通信,来达到与TaskQueue与TimerThread通信的目的。
java.util.concurrent.ThreadPoolExecutor同样也使用到了中介者模式,ThreadPoolExecutor管理着其它对象(Thread、TaskQueue、ThreadFactory、RejectedExecutionHandler)
1.22 备忘录模式
- java.io.Serializable Java中对象实现了这个接口,进行序列化,就是将对象进行快照保存,反序列化就是进行恢复。
1.23 解释器模式
- java.util.Pattern
- java.text.Normalizer
- java.text.Format
2、Spring设计模式示例
2.1 代理模式
Spring的AOP的实现就是依赖了动态代理技术,而动态代理就是使用了代理设计模式,JDK的动态代理/cglib动态代理,Spring也支持与AspectJ的集成。
2.2 工厂方法模式
org.springframework.beans.factory.BeanFactory是Spring容器的顶级工厂接口,它实现工厂方法模式。
2.3 观察者模式
参考文档:Spring 中的观察者模式
事件(ApplicationEvent)、事件监听器(ApplicationListener)、事件发布者(ApplicationContextPublisher)、 事件管理(ApplicationEventMulticaster)
2.4 单例模式&原型模式
spring配置文件中的bean默认情况下是单例模式scope=”singleton” , 此外还可以配置为prototype、request、session、global session
参考文档:spring中的scope详解
2.5 责任链模式
Spring MVC
: HandlerExecutionChain
= n 个 HandlerInterceptor
+ 1 个 handler
/**
* Handler execution chain, consisting of handler object and any handler interceptors.
* Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
*
* @author Juergen Hoeller
* @since 20.06.2003
* @see HandlerInterceptor
*/
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
// 非相关代码 此处省略........
}
2.6 策略模式
2.6.1 Spring Reource接口
在spring中org.springframework.core.io.Resource是资源访问策略,但具体采用哪种策略实现,Resource 接口并不理会。客户端程序只和 Resource 接口耦合,并不知道底层采用何种资源访问策略,
这样应用可以在不同的资源访问策略之间自由切换。
Spring 为 Resource 接口提供了如下实现类:
- UrlResource:访问网络资源的实现类。
- ClassPathResource:访问类加载路径里资源的实现类。
- FileSystemResource:访问文件系统里资源的实现类。
- ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:
- InputStreamResource:访问输入流资源的实现类。
- ByteArrayResource:访问字节数组资源的实现类。
这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。
2.6.2 Spring Validateor 接口
2.7 模板方法模式
spring提供的数据库访问的模板类JdbcTemplate、消息处理的模板类JMSTemplate、HTTP通信的模板类RestTemplate,还有RedisTemplate、也是使用了模板设计模式,但不是上述例子中最典型的模板模式,是一种更简洁、更适合于编码的使用方式。
他没有抽象类,只有一个模板类,通用步骤在当前类中定义,需要定制化的步骤通过回调的方式定义。下面举例说明:JdbcTemplate.java 源码如下:
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
@Override
@Nullable
public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
throws DataAccessException {
Assert.notNull(psc, "PreparedStatementCreator must not be null");
Assert.notNull(action, "Callback object must not be null");
if (logger.isDebugEnabled()) {
String sql = getSql(psc);
logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
}
//通用步骤:获取connection
Connection con = DataSourceUtils.getConnection(obtainDataSource());
PreparedStatement ps = null;
try { //通用步骤:获取PrepareStatement
ps = psc.createPreparedStatement(con); //定制化步骤:设置PrepareStatement配置
applyStatementSettings(ps); //定制化步骤:通过回调函数定制化对PrepareStatement的操作,即具体的查库操作
T result = action.doInPreparedStatement(ps);
handleWarnings(ps);
return result;
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
if (psc instanceof ParameterDisposer) {
((ParameterDisposer) psc).cleanupParameters();
}
String sql = getSql(psc); //通用步骤:关闭PrepareStatement
JdbcUtils.closeStatement(ps);
ps = null; //通用步骤:释放connection
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("PreparedStatementCallback", sql, ex);
}
finally {
if (psc instanceof ParameterDisposer) {
((ParameterDisposer) psc).cleanupParameters();
}
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
}
2.8 装饰器模式
spring-data-session中,有一个类SessionRepositoryRequestWrapper
2.9 适配器模式(待补充)
3、JDK线程池
JDK线程池是一个很好的案例,使用到了:享元模式、策略模式(RejectHandlerPolicy)、命令模式(Runnable)、简单工厂模式(ThreadFactory)