使用反射以及泛型技术相结合实现简单工厂模式

1、声明:本文是在参考 设计模式之禅作者里边的设计模式改造而来(cbf4Life cbf4life@126.com )

2、接口可以随意更改替换成别的接口,也可以在其他包引入,(测试例子中的接口是Human),但只满足接口中定义的方法没有参数的情况下。

3、直接上代码:详情看注释。

package com.tiger.simpleFactory;

import java.io.*;
import java.net.URL;
import java.util.*;
/**
 * 目的:获得传入接口的所有实现类的字节码对象
 * @author tiger
 * @Date 2017年9月4日
 */
@SuppressWarnings("all")
public class ClassUtils {
	/**
	 * 获得传入接口的所有实现类的字节码对象
	 * @param clazz 某接口的字节码
	 * @return classList 实现该接口的所有类的字节码集合
	 */
	public static List
   
   
    
     getAllClassByInterface(Class clazz){
		//返回的字节码存于List数组中,供外界调用
		List
    
    
     
      classList = new ArrayList
     
     
      
      ();
		//如果不是接口,则不做处理
		if (clazz.isInterface()) {
			//获得接口所在包的包名
			String packageName = clazz.getPackage().getName();
//			System.out.println("传入的接口的名字:"+clazz.getName());
//			System.out.println("传入的接口所在包的包名:"+packageName);
			try {
				//获得当前包以及子包下的所有类
				List
      
      
       
        allClass = getClasses(packageName);
//				System.out.println("传入的接口所在包下的类数目 = "+allClass.size());
				for (int i = 0; i < allClass.size(); i++) {
//					System.out.println("传入的接口所在包下的类 "+i+":"+allClass.get(i));
					//遍历所获得的类的实例,判断是否为同一个接口,过滤掉不是同一个接口的实例对象
					if (clazz.isAssignableFrom(allClass.get(i))) {
						if (!clazz.equals(allClass.get(i))) {//排除自身
//							System.out.println("实现传入的接口的类 "+i+":"+allClass.get(i));
							classList.add(allClass.get(i));
						}
					}
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
//		System.out.println("实现传入的接口类的数目 =  "+classList.size());
		return classList;
	}
	/**
	 * 获取该包下的所有类的字节码文件对象
	 * 例如:new File("字节码文件路径名");
	 * @param packageName 包名
	 * @return classes 字节码文件对象
	 * @throws IOException
	 * @throws ClassNotFoundException 
	 */
	private static List
       
       
         getClasses(String packageName) throws IOException, ClassNotFoundException{ //获得类加载器 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //包路劲名格式转换,系统下的路径分隔符为'/' String path = packageName.replace(".", "/"); //获得改路径下的所有类的一个枚举 Enumeration 
        
          resources = classLoader.getResources(path); //将该路劲下的所有类的实例的放入List集合中 ArrayList 
         
           dirs = new ArrayList 
          
            (); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); //new 出文件对象,之后将其添加到List集合中 dirs.add(new File(resource.getFile())); } //遍历出所有类。。。 List 
           
             classes = new ArrayList 
            
              (); for (File directtory : dirs) { //向集合中添加另外一个集合 classes.addAll(findClass(directtory, packageName)); } return classes; } /** * 查找出某文件夹下的所有.class文件 * @param directtory * @param packageName 文件/文件夹路径名 * @return * @throws ClassNotFoundException */ private static List 
             
               findClass(File directtory,String packageName) throws ClassNotFoundException{ List 
              
                classes = new ArrayList 
               
                 (); //判断是否存在,不存在则直接返回,不需要执行下边代码 if (!directtory.exists()) { return classes; } //获得所有文件 File[] files = directtory.listFiles(); for (File file : files) { //判断是否为文件夹 if (file.isDirectory()) {//如果它为文件夹 assert !file.getName().contains("."); //递归调用,目的是要找出所有字节码文件,之后把字节码文件加入List集合返回给外界调用。 classes.addAll(findClass(file, packageName+ "." + file.getName())); }else if (file.getName().endsWith(".class")) {//如果查找出带有.class,说明是字节码文件 //全限定名 = 包名 + 类名 --》截取名称,去除.class classes.add(Class.forName(packageName+ "." + file.getName().substring(0,file.getName().length() - 6))); } } return classes; } }package com.tiger.simpleFactory; import java.util.List; /** * 类的创建工厂,利用了反射和泛型技术 * @author tiger * @Date 2017年9月4日 */ @SuppressWarnings("all") public class InstanceFactory { /** * 你输入什么类,它就给你产生什么类的实例 * 利用泛型,传入什么对象,就返回什么对象 * @param clazz 实现类的字节码 * @return */ public static 
                
                  T createInstance(Class clazz){ T t = null; try { //利用反射创建类的实例对象,全限定名:clazz.getName() t = (T) Class.forName(clazz.getName()).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return t; } /** * 随机实例化接口下的一个类,这个工厂依赖上边的工厂 * @param clazz 接口类的字节码 * @return */ public static 
                 
                   T createInstance_random(Class clazz){ T t = null; //获取接口下的所有实现类的字节码对象 List 
                  
                    instance_list = ClassUtils.getAllClassByInterface(clazz); //定义一个随机数 int rand = (int) (Math.random()*instance_list.size()); t = createInstance(instance_list.get(rand)); return t; } }package com.tiger.simpleFactory; import java.lang.reflect.Method; /** * 执行某类的所有方法,需要传入两个参数 * 1、类的字节码对象 * 2、类的实例对象 * @author tiger * @Date 2017年9月4日 */ public class InvokeMethods { /** * 执行某类的所有方法(支持所执行的方法中没有参数的情况) * @param clzz 类的字节码对象 * @param obj 类的实例对象 * @throws NoSuchMethodException * @throws Exception */ public static void invokeMethods(Class 
                    clzz,Object obj) throws NoSuchMethodException, Exception{ //获取该接口下的所有方法名,之后将其传入执行方法的方法中 Method[] methods = getMethod(clzz); for (Method method : methods) { String str = method.toString(); //提取方法名 (例如:laugh,不要后边的括号以及前边的包名、类名) String methodName = str.substring(str.lastIndexOf(".")+1,str.length()-2); Method m = callMethod(clzz, methodName); //这里的方法执行顺序不固定 m.invoke(obj); } } /** * 通过类的字节码获取类中所有方法 * @param clzz 类的字节码对象 */ private static Method[] getMethod(Class 
                    clzz){ //包括私有方法(getDeclaredMethods) Method[] methods = clzz.getDeclaredMethods(); return methods; } /** * 获取指定方法,并执行此方法 invoke * @param clzz 类的字节码对象 * @param name 方法名 * @param types 参数列表 * @return m 方法执行对象 * @throws NoSuchMethodException * @throws Exception */ private static Method callMethod(Class 
                    clzz,String mName,Class 
                   ...types) throws NoSuchMethodException, Exception{ //传入方法名和类型参数[类型.class](有多少传多少) Method m = clzz.getDeclaredMethod(mName,types); //公开权限,以可以操作执行所有方法(包括私有方法) m.setAccessible(true); return m; } } package com.tiger.simpleFactory; /** * 人类接口 * @author tiger * @Date 2017年9月4日 */ interface Human { //首先定义什么是人类 //1、人是会笑的 void laugh(); //2、人会哭 void cry(); //人会说话 void talk(); //...... } /** * 黄种人 * @author tiger * @Date 2017年9月4日 */ class YellowMan implements Human { @Override public void laugh() { System.out.println("YellowMan.laugh()"); } @Override public void cry() { System.out.println("YellowMan.cry()"); } @Override public void talk() { System.out.println("YellowMan.talk()"); } } /** * 黑种人 * @author tiger * @Date 2017年9月4日 */ class BlackMan implements Human { @Override public void laugh() { System.out.println("BlackMan.laugh()"); } @Override public void cry() { System.out.println("BlackMan.cry()"); } @Override public void talk() { System.out.println("BlackMan.talk()"); } } /** * 白种人 * @author tiger * @Date 2017年9月4日 */ class WhiteMan implements Human { @Override public void laugh() { System.out.println("WhiteMan.laugh()"); } @Override public void cry() { System.out.println("WhiteMan.cry()"); } @Override public void talk() { System.out.println("WhiteMan.talk()"); } } package com.tiger.simpleFactory; /** * Client * @author tiger * @Date 2017年9月4日 */ public class Client { public static void main(String[] args) throws NoSuchMethodException, Exception { //产生接口下的指定类 Human instance01 = InstanceFactory.createInstance(YellowMan.class); InvokeMethods.invokeMethods(YellowMan.class, instance01); System.out.println("-------------------------------------"); //产生接口下的随机类 Class 
                    clzz = Human.class; for (int i = 0; i < 100; i++) { System.out.println("第"+(i + 1)+ "个人"); //产生对象 Human instance = InstanceFactory.createInstance_random(clzz); //执行方法 InvokeMethods.invokeMethods(clzz, instance); } } } 
                   
                  
                 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值