设计模式------工厂方法模式

AbstractHumanFactory是一个抽象类,定义了一个八卦炉都具有的整体功能,

 HumanFactory为实现类,完成具体的任务:创建人类;

 Human接口是人类的总称,其三个实现类分别为三类人种;

 NvWa类是一个场景类,负责模拟这个场景,执行相关的任务。

我们定义的每个人种都有两个方法:getColor(获得人的皮肤颜色)和talk(交谈),其源代码如代码清单1所示。


代码清单1 人类总称

public interface Human {

    // 每个人种皮肤都有相应的颜色

    public void getColor();

    // 人类会说话

    public void talk();

}

接口Human是对人类的总称,每个人种都至少具有两个方法,黑色人种、***人种、白色人种的代码分别如代码清单2、3、4所示。


代码清单2 黑色人种

public class BlackHuman implements Human {

    @Override

    public void getColor() {

        System.out.println("黑种人的皮肤颜色是黑色的!");

    }

    @Override

    public void talk() {

        System.out.println("黑人会说话,一般听不懂。");

    }

}

代码清单3 ***人种

public class YellowHuman implements Human {

    @Override

    public void getColor() {

        System.out.println("黄种人的皮肤颜色是***的!");

    }

    @Override

    public void talk() {

        System.out.println("黄种人会说话,一般说的都是双字节。");

    }

}

代码清单4 白色人种

public class WhiteHuman implements Human {

    @Override

    public void getColor() {

        System.out.println("白种人的皮肤颜色是白色的!");

    }

    @Override

    public void talk() {

        System.out.println("白种人会说话,一般都是单字节。");

    }

}

所有的人种定义完毕,下一步就是定义一个八卦炉,然后烧制人类。我们想象一下,女娲最可能给八卦炉下达什么样的生产命令呢?应该是“给我生产出一个***人种(YellowHuman类)”,而不会是“给我生产一个会走、会跑、会说话、皮肤是***的人种”,因为这样的命令增加了交流的成本,作为一个生产的管理者,只要知道生产什么就可以了,而不需要事物的具体信息。通过分析,我们发现八卦炉生产人类的方法输入参数类型应该是Human接口的实现类,这也解释了为什么类图上的AbstractHumanFactory抽象类中createHuman方法的参数为Class类型。其源代码如代码清单5所示。


代码清单5 抽象人类创建工厂

public abstract class AbstractHumanFactory {

    public abstract Human createHuman(Class<? extends Human> clazz);

}

注意,我们在这里采用了JDK 1.5的新特性:泛型(Generic),通过定义泛型对createHuman的输入参数产生两层限制:


必须是Class类型;

必须是Human的实现类;

其中的“?”表示的是,只要实现了Human接口的类都可以作为参数,泛型是JDK 1.5中的一个非常重要的新特性,它减少了对象间的转换,约束其输入参数类型,对Collection集合下的实现类都可以定义泛型。有关泛型详细知识,请参考相关的Java语法文档。


目前女娲只有一个八卦炉,其实现了生产人类的方法,如代码清单6所示。


代码清单6 人类创建工厂

public class HumanFactory extends AbstractHumanFactory {

    @Override

    public Human createHuman(Class<? extends Human> clazz) {

        // 定义一个生产的人种

        Human human = null;

        try {

            human = (Human) Class.forName(clazz.getName()).newInstance();

        } catch (Exception e) {

            System.out.println("人种生成错误!");

        }

        return human;

    }

}

人种有了,八卦炉也有了,剩下的工作就是女娲采集黄土,然后命令八卦炉开始生产,其过程如代码清单7所示。


代码清单7 女娲类

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("\n--造出的第二批人是黑色人种--");

        Human blackHuman = YinYangLu.createHuman(BlackHuman.class);

        blackHuman.getColor();

        blackHuman.talk();

        // 第三次造人,火候刚刚好,优品!***人种

        System.out.println("\n--造出的第三批人是***人种--");

        Human yellowHuman = YinYangLu.createHuman(YellowHuman.class);

        yellowHuman.getColor();

        yellowHuman.talk();

    }

}

人种有了,八卦炉有了,负责生产的女娲也有了,激动人心的时刻到来了,我们运行一下,结果如下所示。


--造出的第一批人是白色人种--


白色人种的皮肤颜色是白色的!


白色人种会说话,一般都是但是单字节。


--造出的第二批人是黑色人种--


黑色人种的皮肤颜色是黑色的!


黑人会说话,一般人听不懂。


--造出的第三批人是***人种--


***人种的皮肤颜色是***的!


***人种会说话,一般说的都是双字节。


哇,人类的生产过程就展现出来了!这个世界就热闹起来了,黑人、白人、黄人都开始活动了,这也正是我们现在的真实世界。以上就是工厂方法模式(没错,对该部分有疑问,请继续阅读下去)。




工厂方法模式的定义

工厂方法模式使用的频率非常高,在我们日常的开发中总能见到它的身影。其定义为:


Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses。定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。


工厂方法模式的通用类图如图2所示。


图2 工厂方法模式通用类图


在工厂方法模式中,


抽象产品类Product负责定义产品的共性,实现对事物最抽象定义;


Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。


工厂方法模式的变种较多,我们来看一个比较实用的通用源码。




抽象产品类代码如代码清单8所示。


代码清单8 抽象产品类

public abstract class Product {

    // 产品类的公共方法

    public void method1() {

        // 业务逻辑处理

    }

    // 抽象方法

    public abstract void method2();

}



具体的产品类可以有多个,都继承于抽象产品类,其源代码如代码清单9所示。


代码清单9 具体产品类

public class ConcreteProduct1 extends Product {

    @Override

    public void method2() {

        // 业务逻辑处理

    }

}

public class ConcreteProduct2 extends Product {

    @Override

    public void method2() {

        // 业务逻辑处理

    }

}

抽象工厂类负责定义产品对象的产生,源代码如代码清单10所示。


代码清单10 抽象工厂类

public abstract class Creator {

    /**

     * 创建一个产品对象,其输入参数类型可以自行设置 通常为String、Enum、Class等,当然也可以为空

     *

     * @param clazz

     * @return

     */

    public abstract Product createProduct(Class<? extends Product> clazz);

}

具体如何产生一个产品的对象,是由具体的工厂类实现的,如代码清单11所示。


代码清单11 具体工厂类

public class ConcreteCreator extends Creator {

    @Override

    public Product createProduct(Class<? extends Product> clazz) {

        Product product = null;

        try {

            product = (Product) Class.forName(clazz.getName()).newInstance();

        } catch (Exception e) {

            // 异常处理

        }

        return product;

    }

}

场景类的调用方法如代码清单12所示。


代码清单12 场景类

public class Client {

    public static void main(String[] args) {

        Creator creator = new ConcreteCreator();

        Product product = creator.createProduct(ConcreteProduct1.class);

        /*

        * 继续业务处理

        */

    }

}

  该通用代码是一个比较实用、易扩展的框架,读者可以根据实际项目需要进行扩展。

工厂方法模式的扩展

缩小为简单工厂模式

    我们这样考虑一个问题:一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法就可以了,根据这一要求,我们把上例中的AbstarctHumanFactory修改一下,

最佳实践

工厂方法模式在项目中使用得非常频繁,以至于很多代码中都包含工厂方法模式。该模式几乎尽人皆知,但不是每个人都能用得好。熟能生巧,熟练掌握该模式,多思考工厂方法如何应用,而且工厂方法模式还可以与其他模式混合使用(例如模版方法模式、单例模式、原型模式等),变化出无穷的优秀设计,这也正是软件设计和开发的乐趣所在。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章