例子:女娲造人
类图:
这个过程我们就用程序来实现,首先定义一个人类的总称:
/**
* Created by xpeng on 2018/5/1.
* 定义一个人类的统称
*/
public interface Human {
//首先定义什么是人类
//人是会笑的
public void laugh();
//人类还会哭
public void cry();
//人类会说话
public void talk();
}
然后定义具体的人类:
/**
* Created by xpeng on 2018/5/1.
* 黄色人类
*/
public class YellowHuman implements Human {
@Override
public void cry() {
Log.e("xyz","黄色人类会哭");
}
@Override
public void laugh() {
Log.e("xyz","黄色人类会笑");
}
@Override
public void talk() {
Log.e("xyz","黄色人类会说话");
}
}
/**
* Created by xpeng on 2018/5/1.
* 白色人类
*/
public class WhiteHuman implements Human {
@Override
public void cry() {
Log.e("xyz","白色人类会哭");
}
@Override
public void laugh() {
Log.e("xyz","白色人类会笑");
}
@Override
public void talk() {
Log.e("xyz","白色人类会说话");
}
}
/**
* Created by xpeng on 2018/5/1.
* 黑色人类
*/
public class BlackHuman implements Human {
@Override
public void cry() {
Log.e("xyz","黑色人类会哭");
}
@Override
public void laugh() {
Log.e("xyz","黑色人类会笑");
}
@Override
public void talk() {
Log.e("xyz","黑色人类会说话");
}
}
定义八卦炉(工厂)
/**
* Created by xpeng on 2018/5/1.
* 女娲八卦炉造人
*/
public class HumanFactory {
//定一个烤箱,泥巴塞进去,人就出来,这个老厉害了
public static Human createHuman(Class c) {
Human human = null;
try {
human = (Human) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
Log.e("xyz", " 必须指定人类的颜色 ");
} catch (IllegalAccessException e) {//定义的人类有问题
Log.e("xyz", " 人类定义错误! ");
} catch (ClassNotFoundException e) {
Log.e("xyz", " 混蛋,你指定的人类找不着 ");
}
return human;
}
}
女娲大神造人了
Log.e("xyz"," 造出的第一批人是这样的:白人 ");
Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
whiteHuman.cry();
whiteHuman.laugh();
whiteHuman.talk();
Log.e("xyz"," 造出的第二批人是这样的:黑人 ");
Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
blackHuman.cry();
blackHuman.laugh();
blackHuman.talk();
Log.e("xyz"," 造出的第二批人是这样的:黄色人类 ");
Human yellowHuman = HumanFactory.createHuman(YellowHuman.class);
yellowHuman.cry();
yellowHuman.laugh();
yellowHuman.talk();
人有了,但是这样创建太累了,神仙也会累的,那怎么办?我塞进去一团泥巴,随机出来一群人,管他什么颜色呢,只要是人就行。
类图:
/**
* Created by xpeng on 2018/5/1.
* 女娲八卦炉造人
*/
public class HumanFactory {
//定一个烤箱,泥巴塞进去,人就出来,这个老厉害了
public static Human createHuman(Class c) {
Human human = null;
try {
human = (Human) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
Log.e("xyz", " 必须指定人类的颜色 ");
} catch (IllegalAccessException e) {//定义的人类有问题
Log.e("xyz", " 人类定义错误! ");
} catch (ClassNotFoundException e) {
Log.e("xyz", " 混蛋,你指定的人类找不着 ");
}
return human;
}
//女娲生气了,把一团泥巴塞到八卦炉,爱产生啥人类就啥人类
public static Human createHuman() {
Human human = null;//定义一个类型的人类
try {
//定义了多少人类
List<Class> concreateHumanList = ClassUtils.getAllClassByInterface(Human.class);
//八卦炉自己开始想烧出什么人就什么人
Random random = new Random();
int rand = random.nextInt(concreateHumanList.size());
human = createHuman(concreateHumanList.get(rand));
}catch (Exception e){
Log.e("xyz","这里需要好好思考研究");
}
return human;
}
}
女娲生气了,把一团泥巴塞进去,爱出来什么颜色的人类随意
//女娲生气了,把一团泥巴塞到八卦炉,爱产生啥人类就啥人类
public static Human createHuman() {
Human human = null;//定义一个类型的人类
try {
//定义了多少人类
List<Class> concreateHumanList = ClassUtils.getAllClassByInterface(Human.class);
//八卦炉自己开始想烧出什么人就什么人
Random random = new Random();
int rand = random.nextInt(concreateHumanList.size());
human = createHuman(concreateHumanList.get(rand));
}catch (Exception e){
Log.e("xyz","这里需要好好思考研究");
}
return human;
}
这里还需要一个类,ClassUtils
/**
* Created by xpeng on 2018/5/2.
*/
public class ClassUtils {
//给一个接口,返回这个接口的所有实现类
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 (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return returnClassList;
}
//从一个包中查找所有的类,在jar包中不能查找
private static List<Class> getClasses(String packageName) throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
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;
}
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();
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;
}
}
这个ClassUtils可是个宝,用处可大了去了,可以由一个接口查找所有实现的类,也可以由父类查找到所有的子类,这个要自己修改一下,需要思考一下
完整类图:
总结一下,特别是增加了createHuman()后,是不是这个工厂vhangde扩展性更好了?只要你继续集成Human接口就成了,然后啥也不用修改就可以生产了,具体产多少,八卦炉说了算,简单工厂模式就是这么简单。
工厂方法模式还有一个非常重要的应用,就是延迟始化,直接从内存中拿就行了,怎么实现呢,很简单:
/**
* Created by xpeng on 2018/5/1.
* 女娲八卦炉造人
*/
public class HumanFactory {
//定义一个MAP,初始化过的Human对象都放在这里
private static HashMap<String,Human> humans = new HashMap<String,Human>();
//定一个烤箱,泥巴塞进去,人就出来,这个老厉害了
public static Human createHuman(Class c) {
Human human = null;
try {
//如果MAP中有,则直接从中取出,不用初始化
if (humans.containsKey(c.getSimpleName())){
//产生一个人类
human = humans.get(c.getSimpleName());
}else {
human = (Human) Class.forName(c.getName()).newInstance();
//放到MAP中
humans.put(c.getSimpleName(),human);
}
} catch (InstantiationException e) {
Log.e("xyz", " 必须指定人类的颜色 ");
} catch (IllegalAccessException e) {//定义的人类有问题
Log.e("xyz", " 人类定义错误! ");
} catch (ClassNotFoundException e) {
Log.e("xyz", " 混蛋,你指定的人类找不着 ");
}
return human;
}
//女娲生气了,把一团泥巴塞到八卦炉,爱产生啥人类就啥人类
public static Human createHuman() {
Human human = null;//定义一个类型的人类
try {
//定义了多少人类
List<Class> concreateHumanList = ClassUtils.getAllClassByInterface(Human.class);
//八卦炉自己开始想烧出什么人就什么人
Random random = new Random();
int rand = random.nextInt(concreateHumanList.size());
human = createHuman(concreateHumanList.get(rand));
}catch (Exception e){
Log.e("xyz","这里需要好好思考研究");
}
return human;
}
}
就是定义一个MAP,这个类初始化很消耗资源的情况下比较实用,比如你要连接硬件,或者初始化一个类需要准备比较多的条件(参数),通过这种方式可以减少项目的复杂度。
最后引入一个问题:人是有性别的啊,有男有女,你这怎么没区别,这个需要下一个讲的模式:抽象工厂模式