1、设计模式之工厂
工厂模式是我们最常用的设计模式,学好这个模式当然可以事半功倍,不用关心如何创建,只需要根据相应的需求去获取相应的对象。
假如我们现在需要得到一个Ipod对象和Mac对象,可能在之前,我们的Ipod和Mac都是new出来了,相当于我们的程序依赖了Ipod类和Mac,但是使用了工厂我们就可以部分解耦,将创建和使用分离。
设计模式有一条原则,对象要么构造其他对象,要么使用其他对象,绝对不要两者兼顾。如果遵守这一约束,最终可以降低耦合度。
例如,之前的demo的类图如下:
新依赖关系:
对于使用者的角度来说只需要得到这些对象即可,并不需要这些对象是如何创建的。对于创建者AppleFactory来说,只需要创建并且实例化对象即可,并不需要知道如何使用。这种关注点的分离既加强了内聚性,又降低了耦合度。
2、基础的简单工厂
简单工厂是最基本的工厂模式的应用,其实在很多场合简单工厂就已经很适用了。
大致代码如下:
1
2
3 package factory;
4
5
6
7 import java.util.HashMap;
8
9 import java.util.Map;
10
11
12
13 /**
14
15 * User: <a href="mailto:czy88840616@163.com">czy</a>
16
17 * Date: 2010-1-23
18
19 * Time: 20:28:13
20
21 * To change this template use File | Settings | File Templates.
22
23 */
24
25 public class AppleSimpleFactory {
26
27
28
29 private static Map<String, Object> beanMap = new HashMap<String, Object>();
30
31
32
33 /**
34
35 * Method getBean ...
36
37 *
38
39 * @param beanName of type String
40
41 * @return Object
42
43 */
44
45 public Object getBean(String beanName) {
46
47 if(beanMap.containsKey(beanName)) {
48
49 return beanMap.get(beanName);
50
51 }
52
53
54
55 return null;
56
57 }
58
59
60
61 /**
62
63 * Method init ...
64
65 */
66
67
68
69 public void init() {
70
71 beanMap.put("Ipod", new Ipod());
72
73 beanMap.put("Mac", new Mac());
74
75 }
76
77
78
79 }
80
81
我们创建了一个简单的apple工厂,里面创建了两个对象ipod和mac,当我们需要ipod对象的时候就可以直接get出来使用,不需要通过new来新建。
3、抽象了的工厂—抽象工厂abstract factory
抽象工厂类似于将工厂再抽象一层,让关注点不在于怎么创建,而在于创建不同的方式。
例如,A工厂生产ipod的时候需要打印A的牌子,而B工厂生产的时候需要打B的牌子,生产的产品都是一样的,都是ipod,但是其中的工序和方式不同。
例如:
package factory;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:czy88840616@gmail.com">czy</a>
* @since 2010-2-28 22:03:50
*/
public abstract class MyAbstractFactory {
protected static Map<String, Object> beanMap = new HashMap<String, Object>();
public abstract void create();
public abstract Product getProduct(String className);
}
A工厂的方法:
package factory;
/**
* @author <a href="mailto:czy88840616@gmail.com">czy</a>
* @since 2010-2-28 22:16:05
*/
public class MyAbstractFactoryImpl extends MyAbstractFactory {
@Override public void create() {
Ipod iPod = new Ipod();
iPod.pasteSign("made by A factory");
beanMap.put("Ipod", new Ipod());
beanMap.put("Mac", new Mac());
}
@Override public Product getProduct(String className) {
if(beanMap.containsKey(className)) {
return (Product) beanMap.get(className);
}
return null;
}
}
B工厂方法类似,其中最主要的就是贴牌的不同。
抽象工厂用于创建相同的产品但是方式不同的地方。
4、singleton模式
单例模式主要为了控制对象的数目,在使用过程中,只有一个对象存在。
单例模式的工作原理是,用一个特殊的方法来实例化所需的对象:调用这个方法,检查对象是否已经实例化,如果已经实例化,就返回该对象的一个引用,如果尚未实例化,该方法实例化对象并返回新实例的引用。为了确保这是实例化这个对象的唯一方法,需要将这个类的构造函数定义为保护或者私有的。
一般Singleton模式通常有几种形式:
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
第二种形式:
public class Singleton {
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance==null)
instance=new Singleton();
return instance;
}
}
两种的区别是:第二种是lazy加载方式,只有第一次会被初始化,而之后的都可以直接调用。但是第二种会有并发的问题,没有使用synchronized的时候会出现多个实例并存的问题。
Singleton是邪恶的
http://www.jdon.com/jivejdon/thread/17578
深入singleton可能会演变成double-checked locking (DCL) 模式,比较使用于多线程的情况。
5、spring 的beanFactory
现在工厂模式基本上都可以被spring的core取代,DI的方式已经大量应用于项目。
Spring创建工厂的接口为beanFactory,默认的像applicationContext都是继承于此接口。
Spring提供了一些标志接口,用来改变BeanFactory中的bean的行为。它们包括InitializingBean和DisposableBean。实现这些接口将会导致BeanFactory调用前一个接口的afterPropertiesSet()方法,调用后一个接口destroy()方法,从而使得bean可以在初始化和析构后做一些特定的动作。
Debug了spring的源码后,发现spring在创建bean前进行了许多的操作。
在org.springframework.context.support.AbstractApplicationContext的refresh()方法中。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
红色部分代码为spring创建和放入beanfacoty的主要代码。
跟踪spring的初始化过程来看,最终进行的初始化类的工作在org.springframework.beans.BeanUtils类的instantiateClass方法中。
public static Object instantiateClass(Class clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null");
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
return instantiateClass(clazz.getDeclaredConstructor((Class[]) null), null);
}
catch (NoSuchMethodException ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
最底层的实现一定是为jdk的反射方式。
public static Object instantiateClass(Constructor ctor, Object[] args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor.getDeclaringClass(),
"Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor.getDeclaringClass(),
"Has the class definition changed? Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor.getDeclaringClass(),
"Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor.getDeclaringClass(),
"Constructor threw exception", ex.getTargetException());
}
}