欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式-工厂模式-简单工厂模式+反射+配置文件+泛型

程序员文章站 2022-03-09 20:29:50
...

一、概念

1.1 什么是工厂模式

参考资料:

1.2 什么是反射

参考资料:JAVA中的反射机制

二、优势

1、支持多态
2、代码复用,使得同一段代码适应更多不同场景;
3、工厂使得调用方与被调用方实现解耦,减少依赖;
4、抽象工厂在具体类修改扩张的时候,调用方不用修改代码;

三、劣势

四、简单工厂+反射+配置文件+泛型的实现

4.1 实现思路

以工具作为对象分析:

1、定义工具

  • 创建工具接口Tools,定义工具功能;
  • 创建飞机、车、船抽象类,实现工具接口Tools,定义这3类工具的功能;
  • 创建大飞机、小飞机、大车、小车、大船、小车具体类分别继承飞机、车、船抽象类,说明具体的功能;

2、定义配置文件

  • 配置文件modelTest.properties存放每个具体类的全类名;

3、定义工厂

  • 工厂加载配置文件
  • 工厂提供生产具体类的方法,该方法具备根据参数名生产具体类的能力;
    • 根据参数从加载的配置文件中获取具体类的全类名;
    • 根据全类名利用反射创建具体的工具类;
    • 方法返回值为泛型,支持各种具体类的实例化;

4、定义用户

  • 用户通过调用工厂中的生产方法,将需要创建的类的标志以参数的形式传递过去,进行工具类实例创建;
  • 需要创建的类的标志:配置文件中全类名的key

4.2 UML类图

«interface» Tools +void effect Aircraft Ship Vehicle VehicleSmall VehicleBig ShipBig ShipSmall AircraftBig AircraftSmall ModelFactoryDemo ToolsFactory -Properties properties T getInstance modelTest aircraft_big aircraft_sml ship_big ship_sml vehicle_big vehicle_sml 调用getInstance(String nameKey) 调用modelTest配置文件 具体类被指向而生产对应实例

4.3 定义抽象工具(接口)

工具 ==> 飞机、车子、船

package cn.com.study.demo.modelFactory.po;

/**
 * 工具接口
 * @author Mr.qing
 *
 */
public interface Tools {

	/**
	* 工具的作用
	*/
	public abstract void effect();

}

/**
* 飞机
* @author Mr.qing
*
*/
public abstract class Aircraft implements Tools {

	/**
	 * 飞机的作用
	 */
	@Override
	public abstract void effect();

}                                                                 
                                                                                                                       
/**                                                                                                                    
 * 车                                                                                                                   
 * @author Mr.qing                                                                                                     
 *                                                                                                                     
 */                                                                                                                    
public abstract class Vehicle implements Tools {                                                                       
                                                                                                                       
	/**                                                                                                                  
	 * 车的作用                                                                                                              
	 */                                                                                                                  
	@Override                                                                                                            
	public abstract void effect();                                                                                       
}    
                                                                                                                  
/**
 * 船
 * @author Mr.qing
 *
 */
public abstract class Ship implements Tools {

	/**
	 * 船的作用
	 */
	@Override
	public abstract void effect();
}

4.4 定义具体的工具类型

大飞机、小飞机;大车、小车;大船、小船;

package cn.com.study.demo.modelFactory.po.Impl;  
                                                                                                                       

import cn.com.study.demo.modelFactory.po.Aircraft;     
public class AircraftBig extends Aircraft {                                                                            
                                                                                                                       
	@Override                                                                                                            
	public void effect() {                                                                                               
		System.out.println("大飞机拉航空货!");                                                                                  
	};                                                                                                                   
}                                                                                                                      
public class AircraftSmall extends Aircraft {

	@Override
	public void effect() {
		System.out.println("小飞机坐人!");
	};
}


import cn.com.study.demo.modelFactory.po.Vehicle;
public class VehicleBig extends Vehicle {

	@Override
	public void effect() {
		System.out.println("大车公司用!");
	};
}
public class VehicleSmall extends Vehicle {

	@Override
	public void effect() {
		System.out.println("小车家庭用!");
	};
}


import cn.com.study.demo.modelFactory.po.Ship;
public class ShipBig extends Ship {

	@Override
	public void effect() {
		System.out.println("大船拉沙!");
	};
}
public class ShipSmall extends Ship {

	@Override
	public void effect() {
		System.out.println("小船拉游客!");
	};
} 

4.5 定义生成工具的厂子

ToolsFactory.java

package cn.com.study.demo.modelFactory.factory;                                                                                                                                                         
import java.io.IOException;                                                                                            
import java.util.Properties;                                                                                           
                                                                                                                       
import org.slf4j.Logger;                                                                                               
import org.slf4j.LoggerFactory;                                                                                        
import org.springframework.core.io.ClassPathResource;                                                                  
import org.springframework.core.io.support.EncodedResource;                                                            
import org.springframework.core.io.support.PropertiesLoaderUtils;                                                                                      
                                                                                                                       
/**                                                                                                                    
 * 工具工厂口                                                                                                              
 * @author Mr.qing                                                                                                     
 *                                                                                                                     
 */                                                                                                                    
public abstract class ToolsFactory {                                                                                   
	                                                                                                                     
	private static final Logger logger = LoggerFactory.getLogger(ToolsFactory.class);                                    
	                                                                                                                     
	static Properties properties = null;                                                                                 
	                                                                                                                     
	public static <T>T getInstance(String nameKey){                                                                      
		                                                                                                                 
		//加载配置文件                                                                                                         
		init();                                                                                                          
		                                                                                                                 
		T instance = null;                                                                                               
		//从配置文件获取全类名                                                                                                                 
		String className = properties.getProperty(nameKey);                                                              
		                                                                                                                 
		try {                                                                                                            
			Class clazz = Class.forName(className);                                                                      
			//生产具体工具                                                                                                             
			instance = (T)clazz.newInstance();                                                                           
			                                                                                                             
		} catch (ClassNotFoundException e) {                                                                             
			e.printStackTrace();                                                                                         
		} catch (InstantiationException e) {                                                                             
			e.printStackTrace();                                                                                         
		} catch (IllegalAccessException e) {                                                                             
			e.printStackTrace();                                                                                         
		}                                                                                                                
		                                                                                                                 
		return instance;                                                                                                 
		                                                                                                                 
	}                                                                                                                    
	                                                                                                                     
	/**                                                                                                                  
	 * 加载配置文件                                                                                                            
	 * @param isForceLoad 是否强制加载配置文件 是-true                                                                              
	 */                                                                                                                  
	private static void init() {                                                                                         
		                                                                                                                 
		if(properties != null) {                                                                                         
			return;                                                                                                      
		}                                                                                                                
		                                                                                                                 
		                                                                                                                 
		//配置文件加载                                                                                                         
		try {                                                                                                            
			                                                                                                             
			properties = new Properties(System.getProperties());                                                         
            PropertiesLoaderUtils.fillProperties(properties,                                                           
                    new EncodedResource(new ClassPathResource(                                                         
                            "META-INF/res/modelTest.properties"), "UTF-8"));                                           
                                                                                                                       
		} catch (IOException e) {                                                                                        
			logger.error("加载配置文件失败失败", e);                                                                            
            throw new RuntimeException(e);                                                                             
		}                                                                                                                
	}                                                                                                                    
	                                                                                                                     
	/**                                                                                                                  
	 * 加载配置文件                                                                                                            
	 */                                                                                                                  
	static {                                                                                                             
		init();                                                                                                          
	}                                                                                                                    
}  	                                                                                                                     

4.6 配置文件

modelTest.properties

aircraft_big=cn.com.study.demo.modelFactory.po.Impl.AircraftBig
aircraft_sml=cn.com.study.demo.modelFactory.po.Impl.AircraftSmall

ship_big=cn.com.study.demo.modelFactory.po.Impl.ShipBigl
ship_sml=cn.com.study.demo.modelFactory.po.Impl.ShipSmall

vehicle_big=cn.com.study.demo.modelFactory.po.Impl.VehicleBig
vehicle_sml=cn.com.study.demo.modelFactory.po.Impl.VehicleSmall

4.7 用户使用工具

ModelFactoryDemo .java

package cn.com.study.demo.modelFactory;

import cn.com.study.demo.modelFactory.factory.ToolsFactory;
import cn.com.study.demo.modelFactory.po.Impl.AircraftBig;

/**
 * 工厂设计模式demo
 * @author Mr.qing
 *
 */
public class ModelFactoryDemo {
	
	public static void main(String[] args) {
		
		Tools t = ToolsFactory.getInstance("aircraft_big");
		
		t.effect();
		
	}

}

 
执行结果:
	大飞机拉航空货!

4.8 总结

工厂 + 反射 + 配置文件 + 泛型的模式下:

  • 配置文件是工具、工厂、用户之间的纽带:
    • 配置文件存放工具具体类的全类名以及类标识;
    • 用户调用工厂生产工具时,需要生产那种工具,就将该工具类在配置文件中的类标识传递给工厂就可以生产对应工具了;
    • 工厂根据用户传递过来的类标识,从配置文件中获取具体类全类名,利用反射完成对应工具的生产;
  • 在这种情况下:
    • 工厂与工厂生产的产品在编译时是没有关联的,只有在运行时根据实际需要工厂生产具体的产品,解耦很明显;
  • 泛型作用:
    • 泛型扩大了工厂的生产能力,原理工厂只能生产工具类产品,使用泛型后,工厂就是一个全能工厂了,可以生产包括工具在类的所有产品;
    • 只要有对应的产品类,并且在配置文件中完成产品类配置,工厂就可以生产这种产品;

五、应用场景

  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 在很多软件系统中需要更换界面主题或者一键换肤。
  • DAO层支持多种类型的数据库,动态切换时。
  • 不同操作系统代码差异化,可以切换不同操作系统时。

六、应用案例分析

参考资料:

七、参考资料汇总

简单工厂模式、工厂方法模式和抽象工厂模式有何区别?
设计模式之抽象工厂模式
JAVA中的反射机制
Java设计模式及应用场景之《抽象工厂模式》
反射在工厂模式上的应用
IOC的实现原理—反射与工厂模式
SpringIOC底层原理代码实现