码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式之禅之工厂方法模式

时间:2016-08-17 19:52:50      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

工厂方法模式的定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类

样例:女娲通过八卦炉造白种人、黄种人、黑种人。
见代码:

//工厂要生产的人的接口
public interface Human{
//有两个方法
    public void getColor();
    public void talk();
}
//黑种人
public class BlackHuman implements Human {

    @Override
    public void getColor() {
        System.out.println("黑种人的皮肤是黑色的");

    }

    @Override
    public void talk() {
        System.out.println("黑人会说话,一般人都听不懂");
    }

}
//黑种人
public class YellowHuman implements Human {

    @Override
    public void getColor() {
        System.out.println("黄种人的皮肤是黄色的");

    }

    @Override
    public void talk() {
        System.out.println("黄种人会说话,一般人说的都是双字节");

    }

}
//白种人
public class WhiteHuman implements Human {

    @Override
    public void getColor() {
        System.out.println("白种人的皮肤是白色的");

    }

    @Override
    public void talk() {
        System.out.println("白种人人会说话,一般说的都是单子节");

    }

}

下面的代码用到了泛型

//抽象人类创建工厂,泛型限定了输入参数必须是Class类型、必须是Human的实现类
public abstract class AbstractHumanFactory {
    public abstract <T extends Human> T creatHuman(Class<T> c);
}
//人类创建工厂
public class HumanFactory extends AbstractHumanFactory {

    @Override
    public <T extends Human> T creatHuman(Class<T> c) {
        // TODO Auto-generated method stub
        Human human = null;
        try{
            human = (Human)Class.forName(c.getName()).newInstance();
        }catch(Exception e){
            System.out.println("人类生产错误");
            e.printStackTrace();
        }
        return (T)human;
    }

}

ok,现在让我们想一下女娲会给八卦炉下达什么样的生产命令呢?应该是“给我生产一个黄色人种”,而不会是“给我生产一个会走、会跑、会说话、皮肤是黄色的人”,因为这样的命令增加了交流的成本,作为一个生产的管理者,只要知道生产什么就可以了,而不需要失误的具体信息。

现在女娲开始干活了

下面的代码用到了反射机制。我写的反射机制的blog被我删了…不过这个代码挺简单的,可以理解。这里的反射机制也是反射的非常重要的应用。


public class NvWa {

    public static void main(String[] args) {
        AbstractHumanFactory YinYanglu = new HumanFactory();
        System.out.println("--造出的第一批人是白色人种");
        Human whiteHuman = YinYanglu.createHuman(WhiteHuman.class);
        whiteHuman.getColor();
        whiteHuman.talk();
        System.out.println("--造出的第二批人是黑色人种");
        Human blackHuman = YinYanglu.createHuman(BlackHuman.class);
        blackHuman.getColor();
        blackHuman.talk();
        System.out.println("--造出的第一批人是黄色人种");
        Human yellowHuman = YinYanglu.createHuman(YellowHuman.class);
        yellowHuman.getColor();
        yellowHuman.talk();
    }
}

怎么样,是不是辣么灰常简单~
下面是工厂模式的一个比较实用、易拓展的框架,读者可以根据实际项目需要进行拓展

//抽象产品类
public abstract class Product{
    public void method1(){
        //业务逻辑处理
    }
    //抽象方法
    public abstract void method2();

}
//具体的产品类
public class ConcreteProduct01 extends Product{
    public void method2(){
        //业务逻辑处理
    }
}
----------
public class ConcreteProduct02 extends Product{
    public void method2(){
        //业务逻辑处理
    }
}
//抽象工厂类
public abstract class Creator{
    /*
    *创建一个产品对象,其输入参数类型可以自行设置
    *通常为String、Enum、Class等,当然也可以为空
    /*
    //输入参数类型是Class,用的反射机制
    public abstract <T extends Product> T createProduct(Class<T> c);
    /*
    *为了让大家知道为什么用反射机制,这里添加一种输入类型是String的比较一下
    pubic abstract <T extends Product> T creatProduct(String productname);
    */

}
//具体工厂类
public class ContreteCreator extends Creator{
    public <T extends Product> T createProduct(Class<T> c){
        Product product = null;
        try{
            product = (Product)Class.forName(c.getName()).newInstance();
        }catch(Exception e){
            System.out.println("产品创造失败了");
            e.printStackTrance();
        }
    }
    /*public <T extends Product> T createProduct(String productname){
            Product product = null;
            try{
            //反射机制可以避免这些繁琐的判断。并且如果这么写,一点你有了新的产品类,还需要来修改代码,差评~
            if(productname == "productname01") product = new ConcreteProduct01();
            else if(productname == "productname02")product = new ConcreteProduct02();
        }catch(Exception e){
            System.out.println("产品创造失败了");
            e.printStackTrance();
        }
    }
    */
}
//场景类
public class Client{
    public static void main(String[] args){
        Creator creator = new ConcreteCreator();
        Product product = creator.createProduct(ConcreteProduct1.class);
    }
}

工厂方法模式的基本代码就是这些,下面让我们来看一下它的优点

1、首先,良好的封装性,代码结构清晰。一个调用者需要一个具体的产品对象的话,只要知道这个产品的类名(或你使用的字符串)就可以了。
2、工厂方法模式的封装性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类(用反射机制是不用修改的)或拓展一个工厂类,就可以完成“拥抱变化”。
3、屏蔽产品类。产品类如何变化,只要产品接口不变就跟我们没有关系。
4、最后,工厂模式方法是典型的解耦框架。高层模块只需要知道产品的抽象类,别的不用关心,符合迪米特法则。只依赖产品类的抽象,符合依赖倒置原则。使用产品子类替换产品父类,也符合里氏替换原则

还没有结束!

厂方法模式的拓展
1、缩小为简单工厂模式。如果只有一种工厂,那么我们就不需要抽象工厂了,产品类都不需要改变,同时这个唯一工厂的方法设置成static的

public class HumanFactory{
    //这里是
    public static <T extends Human> T createHuman(Class<T> c){
    Human human = null;
        try{
            human = (Human)Class.forName(c.getName()).newInstance();
        }catch(Exception e){
            System.out.println("人类生产错误");
            e.printStackTrace();
        }
        return (T)human;
}

}

2、升级为多个工厂类
当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化,会是代码结构不清晰。例如,如果一个产品类有5个具体实现,每个实现类的初始化(不仅仅是new,还包括对对象设置初始值等)都不相同,如果写在一个工厂方法中,势必会导致该方法类巨大无比。

怎么办呢?

每一种产品都有自己的工厂,并在自己的工厂中初始化自己。意思比较简单,就不再添加代码了,自己尝试一下吧~

设计模式之禅之工厂方法模式

标签:

原文地址:http://blog.csdn.net/tyronerenekton/article/details/52233090

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!