`
IcyFenix
  • 浏览: 359076 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
文章分类
社区版块
存档分类
最新评论

探索设计模式之二——工厂方法模式

阅读更多

2.工厂方法模式(Factory Method Pattern

       上一章介绍了简单工厂模式的作用和使用场景,它能为我们隔离开产品使用者与产品制造者的职责,使得这两部分代码脱离耦合。

 

       在看到简单工厂模式带来的好处的同时,我们也可以预见,随着工厂产品的丰富,每增加一个产品,都将需要修改工厂方法。这是简单工厂的特性——只能处理可预见的情况决定的。然而,频繁的修改代码是我们所不愿意看到的,通过修改代码来增加产品(功能),也违反了设计模式中的“开闭原则”

      

       开闭原则:即“开放-闭合原则”,软件架构应该设计成对于修改来说,代码实体是关闭的,而对于扩展来说,代码实体则是开放的。通俗一点讲,开闭原则是鼓励通过“新增”来代替“变化”。鼓励设计者将业务逻辑抽象化,将逻辑的本质设计成抽象类或者接口,逻辑的具体实践操作设计成具体实现类。

 

现实世界中,业务的本质是相对稳定的,而业务的具体实践则总会不断变化。在逻辑改变的时候,应当做到可以只替换具体实现类,而会不影响到代码的架构。开闭原则是OOAD中的核心原则,在实现功能需求的时候,新增的代码与修改的代码之间的比值,某种程度上可以作为量化衡量一个软件系统的成熟程度的标志。

 

       为了解决简单工厂的这个弊端,需要引入本章的主题:工厂方法模式。工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor),工厂方法模式主要是对“工厂”的封装,提供一个创建者的接口,将产品实例化的步骤延迟到工厂的子类完成,让子类决定需要创建什么产品。

 

目的:

定义创建者的抽象接口,延迟产品实例化到其子类之中,创建的产品一般不再通过传入参数控制,而直接决定于使用了哪个实现类作为其子类。

 

场景:

       随着游戏的发展,只靠机枪兵、喷火兵越来越难以获得战斗胜利了。这时候,机械化的重型武器登上了战争的舞台,战场上的主角,不再只是从兵营一个地方生产出来。司令部为了检验Raynor的设计模式是否能在机械化混合部队中发挥作用,特别举行了一次阅兵仪式……

 

为了简单起见,本次阅兵需要检阅仅两种部队:从兵营生产出来的机枪兵以及从重工厂生产出来的坦克。无论从哪里生产出来,他们都是Terran的部队,实现了ITerranArmy接口,对于本次阅兵来说,此接口只有一个showState()方法。

 

                              

分析:

 

       照例,我们先看一下这次需要涉及到的产品类图及代码:

2.1 战斗部队及工厂的UML

 

public interface ITerranArmy {
    public void showState();
}
 
public class Marine implements ITerranArmy {
    public Marine() {
        System.out.println("训练出一个机枪兵");
    }
 
    public void showState() {
        System.out.println("机枪兵从兵营生产,属于步兵,作战灵活。");
    }
}
 
public class Tank implements ITerranArmy {
    public Tank() {
        System.out.println("制造出一架坦克");
    }
 
    public void showState() {
        System.out.println("坦克从重工厂生产,属于机械部队,威力强大。");
    }
}
 

 

       如果现在继续使用简单工厂来完成这个需求的话,随着各种兵种的登场,工厂类的代码将会出现一长串的if语句,而且每增加一种兵种,就必须修改一次工厂类。显然,根据上面的讨论,这样的代码是不可忍受的。

 

       根据当前的实际情况,Raynor对简单工厂做出了一些扩展:首先建立后勤部,它不负责生产任何部队,但是任何部队的生产都是由后勤部直接领导,在程序语言中,我们把它叫做“抽象工厂”,在本次实例中,我们把它叫做“ITerranFactory”接口,无论是兵营还是重工厂,都是此接口的一个实现类,在程序语言中,我们把这些实现类叫做“具体工厂”。而场景描述中提到的ITerranArmy接口,在程序语言中则成为“抽象产品”,要生产的机枪兵、坦克都是此接口的实现,成为“具体产品”。

 

       抽象工厂和具体工厂的实现代码如下:

 

//抽象工厂
public interface ITerranFactory {
    public ITerranArmy createArmy();
}

//具体工厂,此工厂生产坦克
public class MachineFactory implements ITerranFactory {
    public ITerranArmy createArmy() {
        return new Tank();
    }
}

//具体工厂,此工厂生产机枪兵
public class SoldierFactory implements ITerranFactory {
    public ITerranArmy createArmy() {
        return new Marine();
    }
}
 

 

       在阅兵的时候,调用代码如下:

 

public class WarField {
    public static void showState(ITerranFactory factory) {
        factory.createArmy().showState();
    }
 
    public static void main(String[] args) {
        // 一般来说,大多应用是将Factory的实现类写在配置文件中。
        // 这样就可以实现通过更换工厂来切换生产产品,而不用修改代码。
        showState(new SoldierFactory());
        showState(new MachineFactory());
    }
}
 

 

 

       从代码上可以看出,我们需要什么产品,不再是靠外界传入参数决定,而是取决于抽象工厂使用的是具体哪个实现类。

 

值得指出的是,虽然示例代码中是直接通过new来创建具体工厂,但在现实编程中,大部分工厂方法模式都是配合这反射来使用的,既可以考虑把“SoldierFactory”、“MachineFactory”等具体实现类写在配置文件中,通过反射代替直接new一个具体工厂对象,这样当增加一个产品,就可以做到对工厂和使用者都不存在任何修改,只需要添加一个新的工厂类,并且配置到配置文件中即可,这就是开闭原则的一个体现。

 

       最终运行结果如下:



  2.2 阅兵仪式运行结果

 

总结:

通过上述阅兵的例子,我们看到工厂方法模式确实给系统架构带来强大而灵活的扩展能力。这种基于多态性设计的模式,使得产品的实例化延迟到具体子类之中,通过替换不同的实现子类就能达到新增和切换产品的目的。

 

       由于本次阅兵效果良好,司令部决定让Raynor领导这些部队对Zerg进行一次大规模的协同作战。前面在简单工厂、工厂方法两种模式中,主要都是围绕这个体产品(MarineFirebatTank等)的创建进行讨论,下一章中,我们将会通过一次“协同作战”看看各种具体对象之间存在互相依赖关系时,如何运用抽象工厂模式(Abstract Factory Pattern)来解决问题。

  • 大小: 4.6 KB
  • 大小: 5.3 KB
分享到:
评论
5 楼 weizoudelu 2017-12-01  
不错,看了博主的好几篇关于设计模式的文章,感觉简单易懂
4 楼 Misaya 2014-01-23  
简单好理解!赞。
3 楼 yuur369 2012-03-18  
工厂方法模式可以理解为在简单工厂的基础,对进行制造的工厂再做一层抽象的封装。由原先的单一工厂变成了现在任意个工厂。添加产品时不需对原来的工厂进行修改,只需添加一个新的工厂就行了。。。。。
2 楼 litianyi520 2010-01-31  
写的很好 ,但是例子举的不好,不够简洁
1 楼 IcyFenix 2010-01-19  
PDF下载见附件,《设计模式探索——星际争霸探险之旅》其他章节请见我博客:
http://icyfenix.iteye.com

相关推荐

    抽象工厂模式 源代码

    ——探索设计模式系列之三 Terrylee,2005年12月12日 概述 在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过...

    asp.net知识库

    ASP.NET 2.0使用Web Part创建应用程序之二(共二) 体验 .net2.0 的优雅(2) -- ASP.net 主题和皮肤 NET2.0系列介绍(一).NET 2.0 中Web 应用程序主题的切换 ASP.NET 2.0 中Web 应用程序主题的切换 2.0正式版中...

    精通QTP——自动化测试技术领航

    5.1 QTP设计模式 5.2 GUI层面向对象的扩展设计 6.1 框架设计理念 6.2 框架设计平台 6.3公共对象管理 6.4 用例设计管理 6.5 公共函数工厂 6.6 测试执行管理 6.7 测试报表管理 6.8 一点写给读者的话语(总结)

    敏捷软件开发.pdf

    28.1 VISITOR设计模式系列 28.2 VISITOR模式 28.3 ACYCLIC VISITOR模式 28.4 DECORATOR模式 28.5 EXTENSION OBJECT模式 28.6 结论 参考文献 第29章 STATE模式 29.1 有限状态自动机概述 29.2 实现技术 ...

    CLR.via.C#.(中文第3版)(自制详细书签)Part2

    《CLR via C#(第3版) 》针对.NET Framework 4.0和多核编程进行了全面更新和修订,是帮助读者深入探索和掌握公共语言运行时、C#和.NET开发的重要参考,同时也是帮助开发人员构建任何一种应用程序(如Microsoft ...

    CLR.via.C#.(中文第3版)(自制详细书签)Part1

    《CLR via C#(第3版) 》针对.NET Framework 4.0和多核编程进行了全面更新和修订,是帮助读者深入探索和掌握公共语言运行时、C#和.NET开发的重要参考,同时也是帮助开发人员构建任何一种应用程序(如Microsoft ...

    CLR.via.C#.(中文第3版)(自制详细书签)

    《CLR via C#(第3版) 》针对.NET Framework 4.0和多核编程进行了全面更新和修订,是帮助读者深入探索和掌握公共语言运行时、C#和.NET开发的重要参考,同时也是帮助开发人员构建任何一种应用程序(如Microsoft ...

    CLR.via.C#.(中文第3版)(自制详细书签)Part3

    《CLR via C#(第3版) 》针对.NET Framework 4.0和多核编程进行了全面更新和修订,是帮助读者深入探索和掌握公共语言运行时、C#和.NET开发的重要参考,同时也是帮助开发人员构建任何一种应用程序(如Microsoft ...

    中文版RFC,共456

    RFC1636 IAB工厂关于在Internet体系结构的安全报告 -2月8-10号, 1994 RFC1643 以太网-类似界面类型的管理对象的定义 RFC1658 字符流设备使用SMIv2管理对象的定义 RFC1661 点对点协议(PPP) RFC1671 向IPng 过渡和其他...

    RFC中文文档-txt

    RFC1636 IAB工厂关于在Internet体系结构的安全报告 -2月8-10号, 1994 RFC1643 以太网-类似界面类型的管理对象的定义 RFC1658 字符流设备使用SMIv2管理对象的定义 RFC1661 点对点协议(PPP) RFC1671 向IPng 过渡和其他...

    rfc中文文档目录,包含部分翻译

    RFC1636 IAB工厂关于在Internet体系结构的安全报告 -2月8-10号, 1994 RFC1643 以太网-类似界面类型的管理对象的定义 RFC1658 字符流设备使用SMIv2管理对象的定义 RFC1661_点对点协议(PPP) RFC1671 向IPng 过渡和...

Global site tag (gtag.js) - Google Analytics