本系列文章共分为六篇:
设计模式(一)设计模式的分类与区别
设计模式(二)创建型模式介绍及实例
设计模式(三)结构型模式介绍及实例
设计模式(四)行为型模式介绍及实例(上)
设计模式(五)行为型模式介绍及实例(下)
设计模式(六)设计模式的常见应用
一、Spring框架中种的设计模式
- 1、简单工厂模式
BeanFactory就是简单工厂模式的体现,根据传入一个唯一标识来获得Bean对象。
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
- 2、单例模式
Spring中bean的默认作用域就是singleton(单例)的。
Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。Spring 实现单例的核心代码:
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...省略了很多代码
try {
singletonObject = singletonFactory.getObject();
}
//...省略了很多代码
// 如果实例对象在不存在,我们注册到单例注册表中。
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
//将对象添加到单例注册表
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
}
}
}
- 3、适配器模式
SpringMVC中的适配器HandlerAdatper 。由于应用会有多个Controller实现,如果需要直接调用Controller方法,那么需要先判断是由哪一个Controller处理请求,然后调用相应的方法。当增加新的Controller,需要修改原来的逻辑,违反了开闭原则(对修改关闭,对扩展开放)。
为此,Spring提供了一个适配器接口,每一种Controller对应一种HandlerAdapter实现类。当请求过来,SpringMVC会调用getHandler()获取相应Controller,然后获取该Controller对应的HandlerAdapter,最后调用HandlerAdapter的 handle()方法处理请求,实际上调用的是Controller的handleRequest() 。每次添加新的Controller时,只需要增加一个适配器类就可以,无需修改原有的逻辑。
常用的处理器适配器: SimpleControllerHandlerAdapter、HttpRequestHandlerAdapter 、AnnotationMethodHandlerAdapter 。 - 4、代理模式
Spring AOP就是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象.而对于没有实现接口的对象,Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
:
使用AOP之后可以把一些通用的功能抽象出来,在在需要用到的地方直接使用即可,这样大大简化了代码量。需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。 - 5、观察者模式
Spring中observer模式常用的地方是listener的实现,如ApplicationListener。 - 6、模板方法模式
用来解决代码重复的问题。比如: JmsTemplate、HibernateTemplate。
比如在使用JdbcTemplate时,开发者只要关注业务代码的实现(增删改查等),数据库的连接、断开等操作不用再关注。
二、JDK中的设计模式
2.1 创建型模式
- 1、抽象工厂模式
比如java.util.Calendar的getInstance()方法:
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
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) {
}
}
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 (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;
}
可以看出,调用Calendar.getInstance方法时,调用到的createCalendar方法就是根据不同国家地区返回对应的日期子类。
- 2、工厂方法模式
比如java.lang.Integer的valueOf(String)方法:
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
parseInt(s,10)方法是按10进制将传进来的字符串参数转换成int数字。因此,整个valueOf(String)方法整体上看:传进来一个参数,创建出一个对象,即是工厂方法模式。
- 3、单例模式
比如java.lang.Runtime的getRuntime()方法:
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
- 4、原型模式
比如Java中的Cloneable接口。
2.2 结构型模式
- 1、适配器模式
比如:InputStreamReader、OutputStreamWriter。 - 2、装饰器模式
比如java.io.BufferedInputStream的BufferedInputStream(InputStream)方法:
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
BufferedInputStream的父类是FilterInputStream,FilterInputStream的父类是InputStream。因此,BufferedInputStream的构造方法就是在不影响正常的功能的情况下,增加一些附属功能,典型的装饰模式。
- 3、外观模式
比如java.util.logging。 - 4、享元模式
比如Integer.valueOf。
2.3 行为型模式
- 1、策略模式
比如线程池的四种拒绝策略、java.util.Comparator的compare()方法:
int compare(T o1, T o2);
Comparator是个接口,继承该接口的类可以自己去定义比较元素的方法。
- 2、模板方法模式
InputStream、OutputStream、AQS等。
比如java.io.InputStream的read(byte b[], int off, int len)方法:
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
该方法定义了固定的方法步骤,但是其中的read()方法是abstract的,不同的实现类可以实现自己的read方法。
- 3、迭代器模式
比如java.util.Iterator,通过迭代器方式进行遍历时,调用的就是该方法里声明的接口:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
- 4、命令模式
如线程池中的Runnable、Callable等。 - 5、责任链模式
比如java.util.logging.Logger的log()方法:
public void log(Level level, String msg) {
if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
doLog(lr);
}
private void doLog(LogRecord lr) {
lr.setLoggerName(name);
final LoggerBundle lb = getEffectiveLoggerBundle();
final ResourceBundle bundle = lb.userBundle;
final String ebname = lb.resourceBundleName;
if (ebname != null && bundle != null) {
lr.setResourceBundleName(ebname);
lr.setResourceBundle(bundle);
}
log(lr);
}
public void log(LogRecord record) {
if (!isLoggable(record.getLevel())) {
return;
}
Filter theFilter = filter;
if (theFilter != null && !theFilter.isLoggable(record)) {
return;
}
//...省略一些代码
}
在log(LogRecord record)里,已经看到了链式的处理。
- 6、解释器模式
比如java.util.regex.Pattern的compile(String regex)方法:
public static Pattern compile(String regex) {
return new Pattern(regex, 0);
}
private Pattern(String p, int f) {
pattern = p;
flags = f;
// to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
if ((flags & UNICODE_CHARACTER_CLASS) != 0)
flags |= UNICODE_CASE;
// Reset group index count
capturingGroupCount = 1;
localCount = 0;
if (pattern.length() > 0) {
compile();
} else {
root = new Start(lastAccept);
matchRoot = lastAccept;
}
}
compile()方法就是解析regex的过程。
- 7、中介者模式
java.util.concurrent.Executor#execute()。
java.util.concurrent.ExecutorService#submit()。