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

来源:互联网 发布:猿题库数据从何来 编辑:程序博客网 时间:2024/06/06 06:43

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,说明是字节码文件//全限定名 = 包名 + 类名   --》截取名称,去除.classclasses.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 {@Overridepublic void laugh() {System.out.println("YellowMan.laugh()");}@Overridepublic void cry() {System.out.println("YellowMan.cry()");}@Overridepublic void talk() {System.out.println("YellowMan.talk()");}}/** * 黑种人 * @author tiger * @Date 2017年9月4日 */class BlackMan implements Human {@Overridepublic void laugh() {System.out.println("BlackMan.laugh()");}@Overridepublic void cry() {System.out.println("BlackMan.cry()");}@Overridepublic void talk() {System.out.println("BlackMan.talk()");}}/** * 白种人 * @author tiger * @Date 2017年9月4日 */class WhiteMan implements Human {@Overridepublic void laugh() {System.out.println("WhiteMan.laugh()");}@Overridepublic void cry() {System.out.println("WhiteMan.cry()");}@Overridepublic 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);}}}


原创粉丝点击