设计模式作为一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,在现代软件开发过程中得到了充分的利用。使代码更容易被他人理解,保证代码的可靠性。对于一个尚未接触过大型软件开发的学生,在软件开发过程中我使用的设计模式也比较少,并且通常是利用现有框架进行软件的开发,因此,我学习了一下在spring框架中所使用到的设计模式,并就此做一些总结和尝试。在java众多开源框架中,作为一个轻量级java开发框架,spring经过十几年的发展,已经成为了java SE/EE最流行的开发框架,无论在架构设计方面还是代码编写方面,都看成行内典范。
Spring中常用的设计模式有九种,下面将选择其中的两种做详细的介绍。
第一种,简单工厂模式。简单工厂模式又叫静态工厂方法模式,但是不属于23种经典模式之一。简单来说,简单工厂模式就是定义一个类来专门创建其他类的实例,被创建的实例通常具有相同的父类。
举一个简单的例子就是小明想请一些同学吃饭,但是他自己又不会做饭,所以小明将同学带到了肯德基,同学们自己点餐,而他只负责付钱。那么在这里,肯德基就是一个食物工厂,同学小红点了一份炸鸡,工厂就实例化一份炸鸡;小华点了一份汉堡,工厂就实例化一份汉堡。所有食物都继承自“食物”接口。
如图创建5个类:
Food接口:
public interface Food {
public void get();
}
Chicken类:
public class Chicken implements Food {
public void get() {
System.out.println("chicken");
}
}
Hamburg类:
public class Hamburg implements Food {
public void get() {
System.out.print("hamburg");
}
}
工厂类:
public class FoodFactory {
public static Food getFood(String food) throws Exception{
if(food.equalsIgnoreCase("chicken")){
return Chicken.class.newInstance();
}else if(food.equalsIgnoreCase("hamburg")){
return Hamburg.class.newInstance();
}else{
System.out.print("There is no such food!");
return null;
}
}
}
最后是测试:
public class Test {
public static void main(String []args) throws Exception {
String xiaohong = "chicken";
String xiaohua = "hamburg";
Food a = FoodFactory.getFood(xiaohong);
Food b = FoodFactory.getFood(xiaohua);
a.get();
b.get();
}
}
输出结果如图所示:
返回了小红和小华点的对应食物。
在spring中,BeanFactory拥有类似的功能,它负责实例化、配置和管理对象。我们一般用的BeanFactory的实现类ApplicationContext,这个类会自动解析我们配置的applicationContext.xml,然后根据我们配置的bean来new对象,将new好的对象放进一个Map中,键就是我们bean的id,值就是new的对象。下面是一个简化版的BeanFactory的应用:
BeanFactory接口:
public interface BeanFactory {
Object getBean(String id);
}
一个BeanFactory的实现类ClassPathXmlApplicationContext,用以读取配置信息:
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans = new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String fileName) throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream(fileName));
List<Element> elements = document.selectNodes("/beans/bean");
for (Element e : elements) {
String id = e.attributeValue("id");
String value = e.attributeValue("class");
Object o = Class.forName(value).newInstance();
beans.put(id, o);
}
}
public Object getBean(String id) {
return beans.get(id);
}
}
配置信息applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="c" class="com.spring.Car"></bean>
<bean id="p" class="com.spring.Plane"></bean>
</beans>
测试类:
public class Test {
public static void main(String[] args) throws Exception {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
Object o = factory.getBean("c");
System.out.println(o.getClass().toString());
}
}
输出结果:
以上就是spring中工厂模式的应用的一个例子。BeanFactory只是其中的一种应用,spring中还有很多工厂模式的应用,留待以后认真学习。
第二种,装饰模式。装饰模式也叫包装器模式,指动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
一个简单的例子就是用户需求打印一句话,那么就可以这样实现:
接口PrintHandler:
public interface PrintHandler {
public String filter(String msg);
}
接口实现类PrintMessage:
public class PrintMessage implements PrintHandler {
public String filter(String msg) {
return msg;
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
PrintHandler ph = new PrintMessage ();
String s = ph.filter("今天天气真好!");
System.out.println(s);
}
}
输出结果为:
现在客户提出了新的需求,需要在输出信息前面加上“提示信息”几个字。直接更改PrintMessage实现类不太好,因为可能在软件其他地方使用到了该方法。那么就可以用到装饰器模式,代码如下:
装饰器类PrintHandlerDecorator
public class PrintHandlerDecorator implements PrintHandler {
private PrintHandler handler;
public PrintHandlerDecorator(PrintHandler handler) {
super();
this.handler = handler;
}
public String filter(String msg) {
return handler.filter(msg);
}
}
具体实现类DetailDecorator:
public class DetailDecorator extends PrintHandlerDecorator {
public DetailDecorator (PrintHandler handler) {
super(handler);
}
public String filter(String content) {
String temp = "提示信息";
temp += super.filter(content);
return temp;
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
PrintHandler mb = new PrintMessage ();
mb = new PrintHandlerDecorator (new DetailDecorator (new PrintMessage ()));
content = mb.filter("今天天气真好");
System.out.println(content);
}
}
以上就是装饰模式的一个简单的例子,在spring中,开发人员最熟悉的装饰模式的应用应该就是dataSource了。有时在项目中需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在spring和hibernate框架中总是配置一个数据源,因而sessionFactory的dataSource属性总是指向这个数据源并且恒定不变,所有DAO在使用sessionFactory的时候都是通过这个数据源访问数据库。但是现在,由于项目的需要,我们的DAO在访问sessionFactory的时候都不得不在多个数据源中不断切换,这就给开发带来了相当大的难度和性能影响。
在spring的applicationContext中可以配置所有的dataSource。这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL等,也可能是不同的数据源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。然后sessionFactory根据客户的每次请求,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
总之,作为一款优秀的框架,spring在设计模式上的应用显得非常巧妙,还需要我更深入的理解学习。