您的当前位置:首页正文

工厂模式

2020-08-13 来源:意榕旅游网
Spring工厂Bean

Spring工厂Bean可以分为3种:静态工厂Bean、实例工厂Bean、实现FactoryBean接口的工厂Bean。

静态工厂Bean:

静态工厂bean默认为singleton模式。

编写一个StaticFactoryBean类,代码如下: package org.shirdrn.entity;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext; public class StaticFactoryBean {

public static java.util.Date getCurrentDate(){ return new java.util.Date(); } }

配置静态工厂Bean:

autowire=\"default\" dependency-check=\"default\" factory-method=\"getCurrentDate\">

因为使用Spring 1.x默认情况下,singleton=true,单例模式。 测试主函数代码如下所示:

public static void main(String[] args) throws InterruptedException { ApplicationContext ctx = new FileSystemXmlApplicationContext(\"src/applicationContext.xml\");

System.out.println(\"getCurrentDate() : \"+ctx.getBean(\"staticFactoryBean\")); Thread.sleep(2000);

System.out.println(\"getCurrentDate() : \"+ctx.getBean(\"staticFactoryBean\")); Thread.sleep(2000);

System.out.println(\"getCurrentDate() : \"+ctx.getBean(\"staticFactoryBean\")); }

使用Thread让线程休眠2000ms,再获取下一次的时间。 测试输出结果如下所示:

getCurrentDate() : Wed Mar 19 17:27:49 CST 2008 getCurrentDate() : Wed Mar 19 17:27:49 CST 2008 getCurrentDate() : Wed Mar 19 17:27:49 CST 2008 可见,返回是同一个工厂实例。

如果在bean的配置中显式指定作用域singleton=false,则返回的就不是同一个实例了。在Spring 1.x版本中,singleton=false就表示是作用域prototype。

如果我们为id为staticFactoryBean的bean元素添加属性singleton=false,则程序无需改动,输出结果却变化了:

getCurrentDate() : Wed Mar 19 17:34:06 CST 2008 getCurrentDate() : Wed Mar 19 17:34:08 CST 2008

getCurrentDate() : Wed Mar 19 17:34:10 CST 2008 实例工厂Bean:

定义实例工厂Bean,InstanceFactoryBean 类的代码如下所示: package org.shirdrn.entity;

public class InstanceFactoryBean { public java.util.Date getCurrentDate(){ return new java.util.Date(); } }

它有一个getCurrentDate()方法。 配置实例工厂Bean如下所示: class=\"org.shirdrn.entity.InstanceFactoryBean\" singleton=\"false\">

factory-bean=\"instanceFactoryBean\" factory-method=\"getCurrentDate\" singleton=\"false\">

测试主函数代码如下所示:

public static void main(String[] args) throws InterruptedException { ApplicationContext ctx = FileSystemXmlApplicationContext(\"src/applicationContext.xml\");

System.out.println(\"instanceFactoryBean: \"+ctx.getBean(\"instanceFactoryBean\")); System.out.println(\"getCurrentDate() : \"+ctx.getBean(\"getCurrentDate\")); Thread.sleep(2000);

System.out.println(\"instanceFactoryBean: \"+ctx.getBean(\"instanceFactoryBean\")); System.out.println(\"getCurrentDate() : \"+ctx.getBean(\"getCurrentDate\")); Thread.sleep(2000);

System.out.println(\"instanceFactoryBean: \"+ctx.getBean(\"instanceFactoryBean\")); System.out.println(\"getCurrentDate() : \"+ctx.getBean(\"getCurrentDate\")); }

测试结果输出如下所示:

instanceFactoryBean: org.shirdrn.entity.InstanceFactoryBean@a470b8 getCurrentDate() : Wed Mar 19 17:37:47 CST 2008

instanceFactoryBean: org.shirdrn.entity.InstanceFactoryBean@18e2b22 getCurrentDate() : Wed Mar 19 17:37:49 CST 2008

instanceFactoryBean: org.shirdrn.entity.InstanceFactoryBean@f84386 getCurrentDate() : Wed Mar 19 17:37:51 CST 2008 所以看到,每次获取的工厂实例都是一个新的实例。 实现FactoryBean接口的工厂Bean:

new

实现FactoryBean接口的工厂Bean,作用域必须是singleton,不可以指定为prototype。 假设有一个实现了FactoryBean接口的工厂Bean为DateFactoryBean,则它必须继承FactoryBean接口类的所有方法,如下所示: package org.shirdrn.entity; import java.util.Date;

import org.springframework.beans.factory.FactoryBean; public class DateFactoryBean implements FactoryBean { public Date getObject() throws Exception { return new Date(); }

public Class getObjectType() { return Date.class; }

public boolean isSingleton() { return true; } }

配置DateFactoryBean如下所示: class=\"org.shirdrn.entity.DateFactoryBean\" abstract=\"false\"

lazy-init=\"default\" autowire=\"default\" dependency-check=\"default\">

测试主函数代码如下所示:

public static void main(String[] args) throws InterruptedException { ApplicationContext ctx = FileSystemXmlApplicationContext(\"src/applicationContext.xml\");

System.out.println(\"&dateFactoryBean: \"+ctx.getBean(\"&dateFactoryBean\")); System.out.println(\"dateFactoryBean: \"+ctx.getBean(\"dateFactoryBean\")); Thread.sleep(2000);

System.out.println(\"&dateFactoryBean: \"+ctx.getBean(\"&dateFactoryBean\")); System.out.println(\"dateFactoryBean: \"+ctx.getBean(\"dateFactoryBean\")); Thread.sleep(2000);

System.out.println(\"&dateFactoryBean: \"+ctx.getBean(\"&dateFactoryBean\")); System.out.println(\"dateFactoryBean: \"+ctx.getBean(\"dateFactoryBean\")); }

测试输出结果如下所示:

&dateFactoryBean: org.shirdrn.entity.DateFactoryBean@8a0d5d dateFactoryBean: Wed Mar 19 17:47:49 CST 2008

&dateFactoryBean: org.shirdrn.entity.DateFactoryBean@8a0d5d dateFactoryBean: Wed Mar 19 17:47:51 CST 2008

&dateFactoryBean: org.shirdrn.entity.DateFactoryBean@8a0d5d dateFactoryBean: Wed Mar 19 17:47:53 CST 2008

new 可以看出,返回的工厂实例以同一个,但是得到的时间却是不同的。

实现FactoryBean接口,如果想要返回工厂的实例,必须在工厂实例前面使用符号“&”,如果直接使用ctx.getBean(\"dateFactoryBean\"),则,返回的是方法getObject()的返回值。 实现FactoryBean接口的工厂Bean,定义和普通的Bean没有任何区别,只是它已经由Spring的IoC容器来自动管理了。

工厂模式在项目中是常常用到的,有人说只有大项目才会用到,小项目是体会不出来.其实使用设计模式与项目的大小没有实质性的联系.设计模式是经验的总结而不是衡量项目大小的标准.

以开发项目的DAO层为例,在项目中客户的需求是常常变动的,临时更换数据库的需求也是常常发生的,那我们要如何解决跨数据库的功能,这里就要使用到抽象工厂模式了.工厂模式常常用于创建多系列化的对象(如Orale系列,MySql系列) 1.首先定义相关接口(与平常的做法没什么区别) Java代码

// 角色表DAO接口 interface IroleDao { void insert();

void update(); }

// 用户表DAO接口 interface IuserDao { void find();

void delete(); }

// 角色表DAO接口 interface IroleDao { void insert();

void update(); }

// 用户表DAO接口 interface IuserDao { void find();

void delete();

} 2.不同的数据库有不同的SQL语句所以实现时必须分数据库来实现

Java代码

// 用户表Oralce数据库DAO

class OracleuserDao implements IuserDao { public void delete() {

System.out.println(\"Oralce 删除用户表数据\"); }

public void find() {

System.out.println(\"Oralce 查询用户表数据\"); } }

// 用户表MySql数据库DAO

class MySqluserDao implements IuserDao { public void delete() {

System.out.println(\"MySql 删除用户数据\"); }

public void find() {

System.out.println(\"MySql 查询用户数据\"); } }

// 角色表Oracle数据库DAO

class OracleroleDao implements IroleDao { public void insert() {

System.out.println(\"Oralce 对角色表插入数据\"); }

public void update() {

System.out.println(\"Oracle 对角色表更新数据\"); } }

// 角色表MySql数据库DAO

class MySqlroleDAO implements IroleDao { public void insert() {

System.out.println(\"MySql 对角色表插入数据\"); }

public void update() {

System.out.println(\"Mysql 对角色表更新数据\"); } }

// 用户表Oralce数据库DAO

class OracleuserDao implements IuserDao {

public void delete() {

System.out.println(\"Oralce 删除用户表数据\"); }

public void find() {

System.out.println(\"Oralce 查询用户表数据\"); } }

// 用户表MySql数据库DAO

class MySqluserDao implements IuserDao { public void delete() {

System.out.println(\"MySql 删除用户数据\"); }

public void find() {

System.out.println(\"MySql 查询用户数据\"); } }

// 角色表Oracle数据库DAO

class OracleroleDao implements IroleDao { public void insert() {

System.out.println(\"Oralce 对角色表插入数据\"); }

public void update() {

System.out.println(\"Oracle 对角色表更新数据\"); } }

// 角色表MySql数据库DAO

class MySqlroleDAO implements IroleDao { public void insert() {

System.out.println(\"MySql 对角色表插入数据\"); }

public void update() {

System.out.println(\"Mysql 对角色表更新数据\"); } }

这里增加了一套DAO的实现 (与平时有所不同,如果有10个数据库就要加上10种不同的实现,比较麻烦呀)

3.定义DAO工厂接口与实现(利用java反射机制生产出你需要的DAO如:userDAO,roleDao)

Java代码

// DAO工厂

abstract class DaoFactory {

public static DaoFactory getInstance(String classname) { DaoFactory dao = null; try {

dao = (DaoFactory) Class.forName(classname).newInstance(); } catch (Exception e) { e.printStackTrace(); }

return dao; }

abstract IuserDao getuserdao();

abstract IroleDao getroledao(); }

// Oralce工厂

class OracleFactory extends DaoFactory { public IroleDao getroledao() { return new OracleroleDao(); }

public IuserDao getuserdao() { return new OracleuserDao(); } }

// MySql工厂

class MysqlFactory extends DaoFactory { public IroleDao getroledao() { return new MySqlroleDAO(); }

public IuserDao getuserdao() { return new MySqluserDao(); } }

// DAO工厂

abstract class DaoFactory {

public static DaoFactory getInstance(String classname) { DaoFactory dao = null; try {

dao = (DaoFactory) Class.forName(classname).newInstance(); } catch (Exception e) { e.printStackTrace(); }

return dao; }

abstract IuserDao getuserdao();

abstract IroleDao getroledao(); }

// Oralce工厂

class OracleFactory extends DaoFactory { public IroleDao getroledao() { return new OracleroleDao(); }

public IuserDao getuserdao() { return new OracleuserDao(); } }

// MySql工厂

class MysqlFactory extends DaoFactory { public IroleDao getroledao() { return new MySqlroleDAO(); }

public IuserDao getuserdao() { return new MySqluserDao(); } }

4. 定义配置文件

Java代码

class Config { // Oralce

static final String ORALCE = \"org.abc.OracleFactory\";

static final String MYSQL = \"org.abc.MysqlFactory\"; }

class Config { // Oralce

static final String ORALCE = \"org.abc.OracleFactory\";

static final String MYSQL = \"org.abc.MysqlFactory\"; }

配置文件可以定义到XML中去(好处:修改配置项之后不需要对JAVA文件进行编译.)

5.测试你的输出的DAO

Java代码

public class Dao {

public static void main(String[] args) {

DaoFactory.getInstance(Config.ORALCE).getroledao().insert(); DaoFactory.getInstance(Config.MYSQL).getroledao().insert(); } }

public class Dao {

public static void main(String[] args) {

DaoFactory.getInstance(Config.ORALCE).getroledao().insert(); DaoFactory.getInstance(Config.MYSQL).getroledao().insert(); } } 总结

使用条件:一系列接口有一系列的实现

如上IuserDao、IroleDao等一系列的接口,他们可以有一系列的实现(Oracle方式、MySql方式)

OracleuserDao、OracleroleDao、MySqluserDao、MySqlroleDAO 组成元素(以上面例子)

一系列接口:IuserDao、IroleDao

一系列实现:Oracle系列、MySql系列

系列工厂类:Oracle系列工厂类、MySql系列工厂类(必须继承抽象工厂类) 抽象工厂类:DaoFactory

因篇幅问题不能全部显示,请点此查看更多更全内容