• 设计模式之java源码-工厂方法模式


    工厂方法模式

    8.1 女娲造人的故事

          东汉《风俗通》记录了一则神话故事:“开天辟辟,未有人民,女娲搏,黄土作人……”,讲述的内容就是大家非常熟悉的女娲造人的故事。开天辟地之初,大地上并没有生物,只有苍茫大地,纯粹而洁净的自然环境,寂静而又寂寞,于是女娲决定创造一个新物种(即人类)来增加世界的繁荣,怎么制造呢? 

          别忘了女娲是神仙,没有办不到的事情,造人的过程是这样的:首先,女娲采集黄土捏成人的形状,然后放到八卦炉中烧制,最后放置到大地上生长,工艺过程是没有错的,但是意外随时都会发生: 

          第一次烤泥人,兹兹兹兹,感觉应该熟了,往大地上一放,哇,没烤熟!于是一个白人诞生了!(这也是缺乏经验的最好证明) 

          第二次烤泥人,兹兹兹兹兹兹兹兹,上一次没烤熟,这次多烤一会儿,放到世间一看,嘿,熟过头了,于是黑人诞生了! 

          第三次烤泥人,兹~~兹~~兹~~,一边烧制一边察看,直到表皮微黄,嘿,真正好,于是黄色人种出现了! 

          这个造人过程是比较有意思的,是不是可以通过软件开发来实现这个过程呢?古人云“三人行,必有我师焉”,在面向对象的思维中,万物皆对象,是对象我们就可以通过软件设计来实现。首先对造人过程进行分析,该过程涉及三个对象:女娲、八卦炉、三种不同肤色的人,女娲可以使用场景类Client来表示,八卦炉类似于一个工厂,负责制造生产产品(即人类):三种不同肤色的人,他们都是同一个接口下的不同实现类,都是人嘛,只是肤色、语言不同,对于八卦炉来说都是它生产出的产品。分析完毕,我们就可以画出如图8-1所示类图。 

    clip_image002

    图8-1 女娲造人类图 

          类图比较简单,AbstractHumanFactory是一个抽象类,定义了一个八卦炉都具有的整体功能,HumanFactory为实现类,完成具体的任务:创建人类;Human接口是人类的总称,其三个实现类分别为三类人种;NvWa类是一个场景类,负责模拟这个场景,执行相关的任务。 

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

    代码清单8-1 人类总称

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface Human {
     
    //每个人种的皮肤都有相应的颜色
     
    public void getColor();
     
    //人类会说话
     
    public void talk();
     
    }

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

    代码清单8-2 黑色人种

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class BlackHuman implements Human {
     
    public void getColor(){
     
    System.out.println("黑色人种的皮肤颜色是黑色的!");
     
    }
     
    public void talk() {
     
    System.out.println("黑人会说话,一般人听不懂。");
     
    }
     
    }

    代码清单8-3 黄色人种

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class YellowHuman implements Human {
     
    public void getColor(){
     
    System.out.println("黄色人种的皮肤颜色是黄色的!");
     
    }
     
    public void talk() {
     
    System.out.println("黄色人种会说话,一般说的都是双字节。");
     
    }
     
    }

    代码清单8-4 白色人种

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class WhiteHuman implements Human {
     
    public void getColor(){
     
    System.out.println("白色人种的皮肤颜色是白色的!");
     
    }
     
    public void talk() {
     
    System.out.println("白色人种会说话,一般都是但是单字节。");
     
    }
     
    }

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

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

    1
    2
    3
    4
    5
    public abstract class AbstractHumanFactory {
     
    public abstract Human createHuman(Class<? extends Human> c);
     
    }

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

    • 必须是Class类型; 
    • 必须是Human的实现类;

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

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

    代码清单8-6 人类创建工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class HumanFactory extends AbstractHumanFactory {
     
    public Human createHuman(Class<? extends Human> c){
     
    //定义一个生产的人种
     
    Human human=null;
     
    try {
     
    //产生一个人种
     
    human = (Human)Class.forName(c.getName()).newInstance();
     
    } catch (Exception e) {
     
    System.out.println("人种生成错误!");
     
    }
     
    return human;
     
    }
     
    }

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

    代码清单8-7 女娲类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    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();
     
    }
     
    }
  • 相关阅读:
    odoo11 外部数据导入方法2
    odoo 11 实现多个字段对应一个查询参数的查询
    ionic 访问odoo11之具体业务类api接口
    ionic访问odoo 11接口
    odoo 11导入外部数据过程记录
    程序发送邮件的思考
    Topshelf的Ioc实现
    查看MS Sqlserver文件大小语句
    TopShelf 自动配置Service测试
    odoo11 添加自定义模块报错问题
  • 原文地址:https://www.cnblogs.com/kexb/p/3651419.html
Copyright © 2020-2023  润新知