设计模式 工厂模式

工厂模式,最重要的是反射。
简单工厂:简单使用java反射
案例:女娲造人

/
* 定义一个人类的统称
*/
public interface Human { 
//首先定义什么是人类
 
 //人是愉快的,会笑的,本来是想用smile表示,想了一下laugh更合适,好长时间没有大笑了;
public void laugh(); 
 
//人类还会哭,代表痛苦
public void cry(); 
 
//人类会说话
public void talk(); 
 
}

接口的实现类:

/**
* 黄色
*/
public class YellowHuman implements Human { 
 
	public void cry() { 
		 System.out.println("黄色人类会哭"); 
	 } 
	public void laugh() { 
		 System.out.println("黄色人类会大笑,幸福呀!"); 
	 } 
	public void talk() { 
		 System.out.println("黄色人类会说话,一般说的都是双字节"); 
	 } 
} 


/**
* 白色
*/
public class WhiteHuman implements Human { 
	public void cry() { 
		 System.out.println("白色人类会哭"); 
	 } 
	public void laugh() { 
		 System.out.println("白色人类会大笑,侵略的笑声"); 
	 } 
	public void talk() { 
		 System.out.println("白色人类会说话,一般都是但是单字节!"); 
	 } 
} 


/**
* 黑色
*/
public class BlackHuman implements Human { 
	public void cry() { 
		 System.out.println("黑人会哭"); 
	 } 
	public void laugh() { 
		 System.out.println("黑人会笑"); 
	 } 
	public void talk() { 
		 System.out.println("黑人可以说话,一般人听不懂"); 
	 } 
} 

工厂要实现的就是这些接口实现类

public class HumanFactory { 
	 
	 //定一个烤箱,泥巴塞进去,人就出来,这个太先进了
	public static Human createHuman(Class c){ 
		 Human human=null; //定义一个类型的人类

		 try { 
		     //c是一个Class类对象
			 human = (Human)Class.forName(c.getName()).newInstance(); //产生一个人类
		  
		  } catch (InstantiationException e) {
		 //你要是不说个人类颜色的话,没法烤,要白的黑,你说话了才好烤
	          System.out.println("必须指定人类的颜色"); 
	      
	      } catch (IllegalAccessException e) { //定义的人类有问题,那就烤不出来了,这是... 
	          System.out.println("人类定义错误!"); 
	     
	      } catch (ClassNotFoundException e) { //你随便说个人类,我到哪里给你制造去?!
	          System.out.println("混蛋,你指定的人类找不到!"); 
	      } 
	      return human; 
    } 
	 
} 

工厂开始工作

public class NvWa { 
public static void main(String[] args) { 
 
	 //女娲第一次造人,白人
	 System.out.println("------------造出的第一批人是这样的:白人-----------------"); 
	 Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class); 
	 whiteHuman.cry(); 
	 whiteHuman.laugh(); 
	 whiteHuman.talk(); 
	 
	 //女娲第二次造人,黑人
	 System.out.println("\n\n------------造出的第二批人是这样的:黑人-----------------"); 
	 Human blackHuman = HumanFactory.createHuman(BlackHuman.class); 
	 blackHuman.cry(); 
	 blackHuman.laugh(); 
	 blackHuman.talk(); 
	 
	 //第三批人了,黄色人类
	 System.out.println("\n\n------------造出的第三批人是这样的:黄色人类-----------------"); 
	
	 Human yellowHuman = HumanFactory.createHuman(YellowHuman.class); 
	 yellowHuman.cry(); 
	 yellowHuman.laugh(); 
	 yellowHuman.talk() 
	 
	 } 
}

改进一下:
01.getAllClassByInterface():
给一个接口,返回这个接口的所有实现类


//给一个接口,返回这个接口的所有实现类
public static List<Class> getAllClassByInterface(Class c){ 
	 List<Class> returnClassList = new ArrayList<Class>(); //返回结果
	 
	 //如果不是一个接口,则不做处理
	 if(c.isInterface()){ 
		 String packageName = c.getPackage().getName(); //获得当前的名
		 try { 
			 List<Class> allClass = getClasses(packageName); //获得当前包以及子包下的所有类
		 //判断是否是同一个接口
			 for(int i=0;i<allClass.size();i++){ 
				 if(c.isAssignableFrom(allClass.get(i))){ //判断是不是一个接口
					 if(!c.equals(allClass.get(i))){ //接口本身不加进去
						 returnClassList.add(allClass.get(i)); 
					 } 
				 } 
			 } 
		 } catch (ClassNotFoundException e) { 
			 e.printStackTrace(); 
		 } catch (IOException e) { 
			 e.printStackTrace(); 
		 } 
	
	 } 
	 return returnClassList; 
} 

isAssignableFrom

如果是A.isAssignableFrom(B)
确定一个类(B)是不是继承来自于另一个父类(A),一个接口(A)是不是实现了另外一个接口(B),或者两个类相同。主要,这里比较的维度不是实例对象,而是类本身,因为这个方法本身就是Class类的方法,判断的肯定是和类信息相关的。

02.getClasses():
从一个包中查找出所有的类,在jar包中不能查找(没有避免jar的包,这个方法没有写协议的区别,File或者jar判断)
输入的是包名
本次实验的接口和接口实现类都放在同一个包中

 
//从一个包中查找出所有的类,在jar包中不能查找
private static List<Class> getClasses(String packageName) 
 throws ClassNotFoundException, IOException { 
     //获得当前的classLoader 
	 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
	 
	 //public String replace(char searchChar, char newChar)  
	 // 把 . 转换成 \ 因为下面是文件操作
	 String path = packageName.replace('.', '/'); 
	 
	 //URL集合,拿到path的全部URL路径
	 Enumeration<URL> resources = classLoader.getResources(path); 
	 
	  //文件集合,通过URL集合,来获取相关的全部文件,这里获取的是包所在的一个目录
	 List<File> dirs = new ArrayList<File>(); 
	 
	 while (resources.hasMoreElements()) { 
		 URL resource = resources.nextElement(); 
		 dirs.add(new File(resource.getFile())); 
	 } 
	 
	 ArrayList<Class> classes = new ArrayList<Class>(); 
	 for (File directory : dirs) { 
		 classes.addAll(findClasses(directory, packageName)); 
	 } 
	 return classes; 
 } 

这个方法中的用到的方法
01.Thread.currentThread().getContextClassLoader()

返回该线程的ClassLoader上下文。线程创建者提供ClassLoader上下文,以便运行在该线程的代码在加载类和资源时使用。如果没有,则默认返回父线程的ClassLoader上下文。

子线程的ClassLoader与父线程的一致

02.我们先了解下ClassLoader下的 getResources() 方法:

// 找出当前环境下/name 的所有的资源磁盘路径(包括jar包和一般文件)
public Enumeration<URL> getResources(String name) ;

一.首先说一个概念,classpath,指的是编译后的class文件、xml、properties等配置文件所在的目录。比如,如果是maven项目,classpath为“项名/target/classes”,如果是普通项目,可能是”项目名/bin”,或者”项目名/build/classes”等等。

二.先解释getResource
getResource是java.lang.Class的方法,也就是由字节码对象调用。
getResource接受一个字符串参数,如果以”/”开头,就在classpath根目录下找(不会递归查找子目录),如果不以”/”开头,就在调用getResource的字节码对象所在目录下找(同样不会递归查找子目录)。
在这里插入图片描述

例子:

System.out.println(Test1.class.getResource("/"));

System.out.println(Test1.class.getResource("Test1.class"));1句,会输出classpath的根目录。

第2句,会输出Test1.class所在目录。

输出结果:

file:/D:/eclipse-workspace/javase/bin/

file:/D:/eclipse-workspace/javase/bin/com/trs/javase/Test1.class

三.getResource与getResources

getResource与getResources 都是【加载当前类加载器以及父类加载器所在路径的资源文件】
/**
 * 1.getResource
 * 加载当前类加载器以及父类加载器所在路径的资源文件
 * 将遇到的第一个资源文件直接返回!!!
 * 比如当前工程类路径有conf/demo.properties文件,引入的第三方jar包也有这个文件
 * 返回的是当前工程下的这个资源文件
**/
  URL url = loader.getResource("conf/demo.properties");      
/**
  * 2.getResources 
  * 加载当前类加载器以及父类加载器所在路径的资源文件
  * 将遇到的所有资源文件全部返回!
  * 比如当前工程类路径有conf/demo.properties文件,引入的第三方jar包也有这个文件
  * 则将这些文件全部返回
*/
 @Override
    public void run(String... args) throws Exception {
        ClassLoader loader = ClassUtils.getDefaultClassLoader();
        URL url = loader.getResource("META-INF/spring.factories");
        System.out.println("Resource :" + url.getPath());
        System.out.println("=====================================");
        Enumeration<URL> enumeration = loader.getResources("META-INF/spring.factories");
        // 打印出所有同名的资源文件
        while (enumeration.hasMoreElements()) {
            URL url1 = enumeration.nextElement();
            System.out.println("Resources :" + url1.getFile());
        }
    }

在这里插入图片描述
由上面的输出可以看出,使用getResource时,只读取了当前模块resources下的MATE-INF/spring.factories文件。使用getResources,则读取到了所有依赖的包resources下的MATE-INF/spring.factories文件。

03.Enumeration接口

public interface Enumeration<E>
//实现 Enumeration 接口的对象,
//它生成一系列元素,一次生成一个。连续调用 nextElement 方法将返回一系列的连续元素。
例如,要输出 Vector<E> v 的所有元素,可使用以下方法:
   for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
       System.out.println(e.nextElement());
Enumeration<E>的  boolean hasMoreElements()

测试此枚举是否包含更多的元素。
返回:
当且仅当此枚举对象至少还包含一个可提供的元素时,才返回 true;否则返回 false。

Enumeration<E>nextElement()

如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
返回:
此枚举的下一个元素。
抛出:
NoSuchElementException - 如果没有更多的元素存在。

04.URL类型
String getFile() 获取此 URL的文件名。

03.findClasses方法:找到该目录中的文件和目录

private static List<Class> findClasses(File directory, String packageName) 
throws ClassNotFoundException { 
	 List<Class> classes = new ArrayList<Class>(); 
	 if (!directory.exists()) { 
		 return classes; 
	 } 
	 File[] files = directory.listFiles(); //得到的是一个 File 类型的数组,返回的是该目录中的文件和目录。

	 for (File file : files) { 
 		if (file.isDirectory()) { //递归
 			assert !file.getName().contains("."); 
 			classes.addAll(findClasses(file, packageName + "." + file.getName())); 
 		} else if (file.getName().endsWith(".class")) { //反射
			 classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); 
		 } 
	 } 
 return classes; 
 }

01.File类中的listFiles()得到的是一个 File 类型的数组,返回的是该目录中的文件和目录。

工厂的新方法:

public class HumanFactory {
	public static Human createHuman(){ 
		 Human human=null; //定义一个类型的人类
	 
		 //首先是获得有多少个实现类,多少个人类
		 List<Class> concreteHumanList = 
		 ClassUtils.getAllClassByInterface(Human.class); //定义了多少人类
		 //八卦炉自己开始想烧出什么人就什么人 
		 Random random = new Random(); 
		 int rand = random.nextInt(concreteHumanList.size()); 
	 
		 human = createHuman(concreteHumanList.get(rand)); 
	 
		 return human; 
	 }
}

工厂开始工作:

public class NvWa { 
public static void main(String[] args) {
	for(int i=0;i<10000000000;i++){ 
		 System.out.println("\n\n------------随机产生人类了-----------------" + i); 
		 Human human = HumanFactory.createHuman(); 
		 human.cry(); 
		 human.laugh(); 
		 human.talk(); 
	 }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值