通过学习spring优秀框架来学习设计模式
单纯的学设计模式是枯燥乏味的,但是设计模式在之前的有篇文章指出作为一个需要进阶的开发人员所必须掌握的内容,那么怎样来学习呢?可以通过学习优秀的框架来认识和研究设计模式,spring框架不用多说是非常棒的框架,所以打算研究其框架来学习设计模式。
模拟spring的工厂模式:
我们知道spring最为核心的就是spring的IOC、AOP这两者所涉及的设计模式是工厂模式和动态代理模式。这里令人着迷的地方是:如何通过外部的配置完成了bean的创建和容器的概念的提出。之所以想起来这一点也是因为现在所做的产品也是通过配置的方式生产对象。
先贴出来在模拟的过程中遇到的坑,目前主要是做后台的处理,因为工作主要做后台设计开发所以spring还是生疏了许多。
org.dom4j.DocumentException: null Nested exception: null
这个异常因为xml文件路径存放的有问题,我读取文件的方式是调用getResourceAsStream()方法,所以应当将文件放到包里面就是和你对应的Java类同一路径级别,即ClassPath下。
java.lang.NoClassDefFoundError: org/jaxen/JaxenException
这个坑是因为maven没有添加下面的两个依赖:
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
还有注意自己的application.xml文件的内容的编写。
下面模拟的是spring的工厂模式:
简单的回顾spring:spring通过外部配置文件完成灵活的创建Bean,即修改外部的配置文件就可以修改生成的bean。内部机制简单的理解是读取xml配置文件将读取配置文件放到map容器中,每个bean 有唯一的id作为容器中map的key值,容器map的value是该bean的全类名。下面用程序简单的模拟这种机制,这里的配置文件其实也可以是properties文件。
方式1:定义properties文件完成这种方式,properties文件位置是在classpath下的
a、 接口BeanFactory代码如下:
public interface BeanFactory {
BeanFactory create();
void test();
}
b、 两个实现类MyBean MyBean2
public class MyBean implements BeanFactory {
@Override
public void test() {
System.out.println("test spring bean factory.......");
}
@Override
public BeanFactory create() {
System.out.println("create my bean....");
return new MyBean();
}
}
public class MyBean2 implements BeanFactory {
@Override
public void test() {
System.out.println("tes2 spring factory.....");
}
@Override
public BeanFactory create() {
System.out.println("create my bean2........");
return new MyBean2();
}
}
测试类
public class TestSpring {
public static void main(String[] args)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
Map<String, Object> beanMap = new HashMap<String, Object>();
Properties properties = new Properties();
properties.load(TestSpring.class.getResourceAsStream("my_bean.properties"));
String calssId = properties.getProperty("id");
beanMap.put(calssId, properties.get("bean"));
Object object = Class.forName((String)beanMap.get(calssId)).newInstance();
System.out.println(object);
BeanFactory bean = (BeanFactory)object;
bean.create();
bean.test();
}
}
properties文件:
id=test
bean=test.my.factory.MyBean2
我们可以修改properties文件中bean的值就可产生MyBean不用修改我们的源代码。
使用XML文件不同就是读取文件的方式不同,xml文件读取的方式如下:
public class TestSpring {
public static void main(String[] args)
throws ClassNotFoundException, InstantiationException, IllegalAccessException,
IOException, DocumentException {
Map<String, Object> beanMap = new HashMap<String, Object>();
// Properties properties = new Properties();
// properties.load(TestSpring.class.getResourceAsStream("my_bean.properties"));
// String calssId = properties.getProperty("id");
// beanMap.put(calssId, properties.get("bean"));
SAXReader reader = new SAXReader();
String classPath = System.getProperty("user.dir");
File file = new File(classPath + "/src/test/my/factory/applicationContext.xml");
InputStream inputStream = new FileInputStream(file);
Document documnet = reader.read(inputStream);
List<Element> elements = documnet.selectNodes("/beans/bean");
for (Element element : elements) {
String classId = element.attributeValue("id");
String className = element.attributeValue("class");
Object object = Class.forName(className).newInstance();
beanMap.put(classId, object);
System.out.println(beanMap.get(classId));
BeanFactory bean = (BeanFactory)beanMap.get(classId);
bean.create();
bean.test();
}
}
}
xml文件如下:
<beans>
<bean id ="test" class="test.my.factory.MyBean"></bean>
<bean id ="test2" class="test.my.factory.MyBean2"></bean>
</beans>
接下来介绍工厂模式和单例模式。
单例模式:
为什么使用单例模式,在自己的项目中也是有需求的,某个连接只需要实例化一次,这就需要我们控制其创建。即单例模式是指某个类的对象创建在整个应用中只允许创建一次,如果创建多个可能会影响其性能或者是业务逻辑不允许的。实现的方法是设置该类的构造方法为私有,且将给类的对象作为类静态属性。代码示例:
public class MyBean3 {
public static MyBean3 myBean3 = new MyBean3();
private MyBean3() {
}
public static MyBean3 getInstance() {
return myBean3;
}
}
验证在应用中的对象是否是同一个:
public class TestSingleton {
public static void main(String[] args) {
MyBean3 myBean = MyBean3.getInstance();
MyBean3 myBean1 = MyBean3.getInstance();
System.out.println(myBean == myBean1);
}
}
最终的输出结果是:true
说明两次创建的对象是同一个对象。也即不管在哪创建该对象调用了getInstance()方法返回实例对象都将是同一个对象,使用的语法是:static、private修饰符。这里注意如果换成其他的构造方法其访问修饰符也将是private。
工厂模式:
工厂模式是指可以生产产品,产品是灵活,可变的。体现了Java语言的多态特性。将对象的创建变成可控的。
示例代码:
public interface BeanFactory {
BeanFactory createObject();
}
public class MyBean implements BeanFactory {
@Override
public BeanFactory createObject() {
System.out.println("create my bean....");
return new MyBean();
}
}
public class MyBean2 implements BeanFactory {
@Override
public BeanFactory createObject() {
System.out.println("create my bean2........");
return new MyBean2();
}
}
测试程序:
<pre name="code" class="java">public class TestFactory {
public static void main(String[] args) {
BeanFactory bean = new MyBean2();
bean.createObject();
}
}
这里将BeanFactory的实例化对象换为MyBean之后就创建的是MyBean
BeanFactory bean = new MyBean();
重要的知识点是:
编译对象和运行时对象,编译时对象就是在编码时的类型,运行时对象是指在运行时对象。在上述的代码中编译对象是BeanFactory运行对象是MyBean,MyBean2。这也是多态的体现于与应用。
个人体会是:
在未应用之前,自己在写代码时根本不知道这个多态,反射的应用,但是在设计模式中多态和反射是应用非常多的。包括在优秀的框架中比如spring就应用了这些东西,当然spring是这些东西,动态代理模式将在后续文章中总结出来。
下面是对于何时使用工厂模式的定位:
在前面的总结中已经提出设计模式是为了解决某个问题提出的,是依赖于问题而存在的解决方案,那么工厂模式解决的问题是:直观的来说需要多次创建具有共性的不同类对象,这些对象有有相同的属性不同的事物抽象外观特征,此时就可以抽象出共同的接口,淋漓尽致体现多态的特性。但如果是较少的对象比如就单个的类,那就不需要再次的抽象出工厂模式,我们可以发现在createObject中就是 new Object 返回一个对象的实例,单个类就不存在和他平行的子类,没有扩展需要,反而多创建了一个接口。
再说明的是,上述程序较为简单,对于createObject()方法返回值还可以是一个反应这些类其他特性的接口。