设计模式:一种可以被重复利用的解决方案
23种设计模式可分为三大类:
创建型:解决对象创建问题
单例模式
工厂方法模式
抽象工厂模式
建造者模式
原型模式
结构型:一些类或对象组合在一起的经典结构
代理模式
装饰模式
适配器模式
组合模式
享元模式
外观模式
桥接模式
行为型:解决类或者对象之间的交互问题
策略模式
模板方法模式
责任链模式
观察者模式
迭代子模式
命令模式
备忘录模式
状态模式
访问者模式
中介者模式
解释器模式
工厂模式通常有三种形态:
简单工厂模式(Simple Factory):不属于23种设计模式之一。简单工厂模式又叫做:静态工厂方法模式。简单工厂模式是工厂方法模式的一种特殊实现
工厂方法模式(Factory Method):是23种设计模式之一
抽象工厂模式(Abstract Factory):是23种设计模式之一
简单工厂模式的角色包括三个:
抽象产品角色
具体产品角色
工厂类角色
代码示例:
抽象产品角色
/**
* 武器(抽象产品角色)
**/
public abstract class Weapon {
//所有的武器都有攻击行为
public abstract void attack();
}
具体产品角色
/**
* 坦克(具体产品角色)
**/
public class Tank extends Weapon{
@Override
public void attack() {
System.out.println("坦克开炮!");
}
}
/**
* 战斗机(具体产品角色)
**/
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机投下原子弹!");
}
}
/**
* 匕首(具体产品角色)
**/
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍他丫的!");
}
}
工厂类角色
/**
* 工厂类角色
**/
public class WeaponFactory {
/**
* 静态方法
* 根据不同的武器类型生产武器
* @param weaponType 武器类型
* @return 武器对象
*/
public static Weapon get(String weaponType){
if (weaponType == null || weaponType.trim().length() == 0) {
return null;
}
Weapon weapon = null;
if ("TANK".equals(weaponType)) {
weapon = new Tank();
} else if ("FIGHTER".equals(weaponType)) {
weapon = new Fighter();
} else if ("DAGGER".equals(weaponType)) {
weapon = new Dagger();
} else {
throw new RuntimeException("不支持该武器!");
}
return weapon;
}
}
测试代码
public class Client {
public static void main(String[] args) {
Weapon weapon1 = WeaponFactory.get("TANK");
weapon1.attack();
Weapon weapon2 = WeaponFactory.get("FIGHTER");
weapon2.attack();
Weapon weapon3 = WeaponFactory.get("DAGGER");
weapon3.attack();
}
}
结果:
简单工厂模式的优点:
客户端程序不需要关心对象的创建细节,需要哪个对象时,只需向工厂索要,初步实现了责任的分离,生产和消费分离。
简单工厂模式的缺点:
工厂类集中了所有产品的创造逻辑,形成一个无所不知的全能类,有人把它叫做上帝类。显然工厂类非常关键,不能出问题,一旦出问题,整个系统瘫痪
不符合OCP开闭原则,再进行系统扩展时,需要修改工厂类
工厂方法模式既保留了简单工厂模式的优点,同时又解决了缺点
工厂方法模式的角色包括:
抽象工厂角色
具体工厂角色
抽象产品角色
具体产品角色
代码:
抽象产品角色
/**
* 武器类(抽象产品角色)
**/
//所有武器都有攻击行为
public abstract void attack();
}
具体产品角色
/**
* 具体产品角色
**/
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("开枪射击!");
}
}
/**
* 具体产品角色
**/
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机发射核弹!");
}
}
抽象工厂角色
/**
* 武器工厂接口(抽象工厂角色)
**/
public interface WeaponFactory {
Weapon get();
}
具体工厂角色
/**
* 具体工厂角色
**/
public class GunFactory implements WeaponFactory{
@Override
public Weapon get() {
return new Gun();
}
}
/**
* 具体工厂角色
**/
public class FighterFactory implements WeaponFactory{
@Override
public Weapon get() {
return new Fighter();
}
}
测试程序
/**
* @author 动力节点
**/
public class Client {
public static void main(String[] args) {
WeaponFactory factory = new GunFactory();
Weapon weapon = factory.get();
weapon.attack();
WeaponFactory factory1 = new FighterFactory();
Weapon weapon1 = factory1.get();
weapon1.attack();
}
}
结果
工厂方法模式优点:
一个调用者想创建一个对象,只要知道其名称就可以
扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
屏蔽产品的具体实现,调用者只关心产品的接口
工厂方法模式缺点:
每次增加一个产品是,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加可系统的复杂度,同时也增加了系统具体类的依赖。
Spring为Bean提供了多种的实例化方式,通常包括四种方式。
通过构造方法实例化
通过简单工厂模式实例化
通过factory-bean实例化
通过FactoryBean<>接口实例化
BookDaoImpl实现类
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("bookDao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
applicationContext.xml配置
测试类
public class AppForInstanceBook {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
注意:无参构造方法如果不存在,将抛出异常BeanCreationException
OrderDao接口和OrderDaoImpl实现类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
OrderDaoFactory工厂类
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");
return new OrderDaoImpl();
}
}
applicationContext.xml配置,factory-method 告诉Spring框架,调用哪个类获取Bean
测试类
public class AppForInstanceOrder {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
}
}
结果
这种方式本质上是:通过工厂方法模式进行实例化
UserDao接口和UserDaoImpl实现类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
UserDaoFactory工厂类
//实例工厂创建对象
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
applicationContext.xml配置,factory-method + factory-bean实现
factory-bean:告诉Spring调用哪个对象
factory-method:告诉Spring调用该对象的哪个方法
测试类
public class AppForInstanceUser {
public static void main(String[] args) {
// //创建实例工厂对象
// UserDaoFactory userDaoFactory = new UserDaoFactory();
// //通过实例工厂对象创建对象
// UserDao userDao = userDaoFactory.getUserDao();
// userDao.save();
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
结果
以上的第三种方式中,factory-bean是我们自定义的,factory-method也是我们自己定义的。
在Spring中,当你编写的类直接实现FactoryBean接口之后,factory-bean不需要指定了,factory-method也不需要指定了。
factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。
FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。
UserDao接口和UserDaoImpl实现类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
定义UserDaoFactoryBean实现FactoryBean
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class> getObjectType() {
return UserDao.class;
}
/*@Override
public boolean isSingleton() {
//true:单例 false:非单例
return false;
}*/
}
applicationContext.xml配置
测试类
public class AppForInstanceUser {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
结果
BeanFactory:Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,“Bean工厂”负责创建Bean对象。BeanFactory是工厂。
FactoryBean:他是一个Bean,是一个能够辅助Spring实例化其他Bean对象的一个Bean
在Spring中,Bean可以分为两类:
普通Bean
工厂Bean(工厂Bean也是一种Bean,只不过这种Bean比较特殊,它可以辅助Spring实例化其它Bean对象。)
Spring其实是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。
所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。
Bean生命周期可以粗略划分为五大步:
实例化Bean(调用无参数构造方法)
Bean属性赋值(调用set方法)
初始化Bean(调用Bean的init方法)
使用Bean
销毁Bean(调用Bean的destroy方法)
graph LR;
A(实例化Bean)-->B(Bean属性赋值)
B-->C(初始化Bean)
C-->D(使用Bean)
D-->E(销毁Bean)
编写测试程序
定义一个Bean
public class User {
private String name;
public User() {
System.out.println("1.实例化Bean");
}
public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}
public void initBean(){
System.out.println("3.初始化Bean");
}
public void destroyBean(){
System.out.println("5.销毁Bean");
}
}
修改配置文件
测试
public class BeanLifecycleTest {
@Test
public void testLifecycle(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println("4.使用Bean");
// 只有正常关闭spring容器才会执行销毁方法
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}
}
结果
注意:
只有正常关闭的Spring容器Bean的销毁方法才会被调用
ClassPathXmlApplicationContext类才有close()方法
配置文件中的init-method指定初始化方法。destroy-method指定销毁方法。
在以上的5步中,第3步是初始化Bean,如果想在初始化前和初始化后添加代码,可以加入“Bean后处理器”。
graph LR;
A(实例化Bean)-->B(Bean属性赋值)
B(Bean属性赋值)-->F(Bean后处理器before执行)
F-->C(初始化Bean)
C-->G(Bean后处理器after执行)
G-->D(使用Bean)
D-->E(销毁Bean)
编写一个类实现BeanPostProcessor类,并且重写before和after方法:
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的before方法执行,即将开始初始化");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
修改配置文件
结果
增加步骤:
在Bean后处理器before之前
在Bean后处理器before之后
在使用Bean之后,或者销毁之前
都是在检查Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口的方法
graph TD;
A(实例化Bean)-->B(Bean属性赋值)
B-->c(检查Bean是否实现了Aware接口,并设置相关依赖)
c-->D(Bean后处理器before执行)
D-->E(检查Bean是否实现了InitializingBean接口,并调用接口方法)
E-->F(初始化Bean)
F-->G(Bean后处理器after执行)
G-->H(使用Bean)
H-->I(检查Bean是否实现了DisposableBean接口,并调用接口方法)
I-->J(销毁Bean)
Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean。
当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean。
当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean。
示例:
实现Aware相关接口,InitializingBean, DisposableBean接口
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
private String name;
public User() {
System.out.println("1.实例化Bean");
}
public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}
public void initBean(){
System.out.println("6.初始化Bean");
}
public void destroyBean(){
System.out.println("10.销毁Bean");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("3.类加载器:" + classLoader);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3.Bean工厂:" + beanFactory);
}
@Override
public void setBeanName(String name) {
System.out.println("3.bean名字:" + name);
}
@Override
public void destroy() throws Exception {
System.out.println("9.DisposableBean destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5.afterPropertiesSet执行");
}
}
编写一个类实现BeanPostProcessor类,并且重写before和after方法:
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("4.Bean后处理器的before方法执行,即将开始初始化");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
修改配置文件
结果
注意:
InitializingBean的方法早于init-method的执行。
DisposableBean的方法早于destroy-method的执行。
Spring 根据Bean的作用域来选择管理方式。
对singleton作用域的Bean进行完整的生命周期管理,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;
而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
有些时候可能会遇到这样的需求,某个java对象是我们自己new的,然后我们希望这个对象被Spring容器管理,怎么实现?
DefaultListableBeanFactory可以实现
示例:
public class User {
}
public class RegisterBeanTest {
@Test
public void testBeanRegister(){
// 自己new的对象
User user = new User();
System.out.println(user);
// 创建 默认可列表BeanFactory 对象
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 注册Bean
factory.registerSingleton("userBean", user);
// 从spring容器中获取bean
User userBean = factory.getBean("userBean", User.class);
System.out.println(userBean);
}
}
结果: