设计模式-工厂方法模式

例子:女娲造人
类图:
这里写图片描述
这个过程我们就用程序来实现,首先定义一个人类的总称:

/**
 * 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,这个类初始化很消耗资源的情况下比较实用,比如你要连接硬件,或者初始化一个类需要准备比较多的条件(参数),通过这种方式可以减少项目的复杂度。
最后引入一个问题:人是有性别的啊,有男有女,你这怎么没区别,这个需要下一个讲的模式:抽象工厂模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值