【返回目录】
我们现在把场景从险象丛生的特工战切换到更为壮观的二战中来,很多人都看过《拯救大兵瑞恩》,这部电影最著名的两场战斗非首和尾莫属,我们就用最后一场战役来举例说明什么是工厂方法吧。
相比诺曼底登陆,最后一场战役出现了更多的武器,天上飞的、地上爬的都有,那么Tom Hanks还能一把M1A1就走遍天下吗,显然不可能,M1A1对付步兵很不错,但要想搞定一辆坦克就很困难了,用它来对付战斗机,纯属扯淡。所以在最后一场战役中出现的武器也是多元化的,负责瞭望的狙击手用的是M1903A4狙击步枪、像Tom Hanks这样的军官用的是汤姆森M1A1冲锋枪、普通士兵用的是伽兰德步枪、对付坦克用到了TNT***、收拾坦克中的残兵用的是手榴弹……总之,武器只有用在合适的目标上在能发挥最大的威力。那么怎么才能知道我到底该用那种武器呢?Tom Hanks绝不可能战斗前先跟每个士兵交代清楚他应该用什么样的武器,因为根本没人知道他们到底会面对什么样的敌人,所以按套路出牌是行不通的,就只能具体问题具体分析了。
同样的,我们在编写程序时可能也常常会碰到类似的问题,我并不知道当前会碰到什么样的需求,所以我不能确定到底应该返回给调用者一个什么对象,在这种情况下,就不得不把决定权下放给负责生成对象的子类了。这也正是Factory Method(工厂方法)模式所适用的场景,我们来看看下面的代码就一目了然了:
1: using System;
2:
3: namespace Autumoon.DesignPatterns.FactoryMethod
4: {
5: public abstract class WeaponBase
6: {
7: public string Name { get; set; }
8:
9: public abstract void Use(object target);
10: }
11:
12: public class Gun : WeaponBase
13: {
14: public bool IsAuto { get; set; }
15:
16: public override void Use(object target)
17: {
18: // TODO: Use this weapon to kill target.
19: }
20: }
21:
22: public class Bomb : WeaponBase
23: {
24: public int Power { get; set; }
25:
26: public override void Use(object target)
27: {
28: // TODO: Use this weapon to kill target.
29: }
30: }
31:
32: public abstract class AbstractBattle
33: {
34: public abstract WeaponBase CreateWeaponByTargetType(string targetType);
35: }
36:
37: public class Battle : AbstractBattle
38: {
39: public override WeaponBase CreateWeaponByTargetType(string targetType)
40: {
41: switch (targetType)
42: {
43: case "Soldier":
44: return new Gun { Name = "M1A1", IsAuto = true };
45: case "Tank":
46: return new Bomb { Name = "TNT", Power = 1000 };
47: default:
48: return null;
49: }
50: }
51: }
52: }
这个时候,Tom Hanks和他的战友们听到了远处的坦克声,是战斗的时候了,拿起武器,冲向胜利!
1: Battle bridgeBattle = new Battle();
2: Gun m1a1 = bridgeBattle.CreateWeaponByTargetType("Soldier") as Gun;
3: Bomb tnt = bridgeBattle.CreateWeaponByTargetType("Tank") as Bomb;