编写程序遇到多分支的情况总是少不了 switch/if
语句。在面向对象编程里大部分的 switch
语句都是可以避免的。使用多态和简单工厂模式可以消除多余的 switch
语句。
简单的需求
编写程序根据序号输出动物的名字和叫声。
序号 |
名字 |
叫声 |
1 |
猫咪 |
喵喵喵? |
2 |
青蛙 |
蛤? |
过程式的实现方式
思路
直接从输入读入数字,用 switch
判断并输出名字和叫声。
代码
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
| class Program { static void Main(string[] args) { Console.Write("请输入序号:"); string no = Console.ReadLine();
switch (no) { case "1": Console.WriteLine("名为猫咪"); Console.WriteLine("叫了一声:喵喵喵?"); break;
case "2": Console.WriteLine("名为青蛙"); Console.WriteLine("叫了一声:蛤?"); break;
default: Console.WriteLine("这种情况是要加钱的!"); break; }
Console.Read(); } }
|
解析
使用了传统的过程式的编程思想。没有多余的 switch
语句。本文完。。。。。。个屁嘞。实际情况中很可能不需要同时输出名字和叫声。所以需要将相关的逻辑封装。
封装的实现方式
思路
将相关的逻辑代码封装到函数中。并将这两个函数封装到一个系统类中。需要时调用即可
代码
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 42 43 44 45 46 47 48 49
| class Program { static void Main(string[] args) { Console.Write("请输入序号:"); string no = Console.ReadLine();
Console.WriteLine(AnimalSystem.Name(no)); Console.WriteLine(AnimalSystem.Sound(no));
Console.Read(); } }
class AnimalSystem { public static string Name(string no) { switch (no) { case "1": return "名为猫咪"; break; case "2": return "名为青蛙"; break; default: return "这种情况是要加钱的!"; break; } }
public static string Sound(string no) { switch (no) { case "1": return "叫了一声:喵喵喵?"; break; case "2": return "叫了一声:蛤?"; break; default: return "这种情况是要加钱的!"; break; } } }
|
解析
名字和叫声的逻辑都封装到 AnimalSystem
中了。但还不够面向对象。
面向对象的实现方式
思路
新建猫咪和青蛙类,继承于动物类。将名字和叫声移到相应的类中。
代码
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| class Program { static void Main(string[] args) { Console.Write("请输入序号:"); string no = Console.ReadLine();
Console.WriteLine(AnimalSystem.Name(no)); Console.WriteLine(AnimalSystem.Sound(no));
Console.Read(); } }
class AnimalSystem { public static string Name(string no) { switch (no) { case "1": return new Cat().Name(); break; case "2": return new Frog().Name(); break; default: return new Animal().Name(); break; } }
public static string Sound(string no) { switch (no) { case "1": return new Cat().Sound(); break; case "2": return new Frog().Sound(); break; default: return new Animal().Sound(); break; } } }
class Animal { public virtual string Name() { return "这种情况是要加钱的!"; } public virtual string Sound() { return "这种情况是要加钱的!"; } }
class Cat : Animal { public override string Name() { return "名为猫咪"; }
public override string Sound() { return "叫了一声:喵喵喵?"; } }
class Frog : Animal { public override string Name() { return "名为青蛙"; }
public override string Sound() { return "叫了一声:蛤?"; } }
|
解析
现在的代码已经足够面向对象了。但是代码中出现了两次 switch
语句。过程式的代码可是只有一次。有没有什么办法既使用面向对象又只使用一次 switch
语句呢?答案是肯定的。使用简单工程模式搭配多态可以做到。
简单工厂的实现方式
思路
两次 switch
语句出现在 序号→名字 和 序号→叫声 中。先使用简单工厂模式产生 序号→类型 的转换,这时需要一次 switch
语句。之后利用面向对象的多台性质产生 类型→名字 和 类型→叫声 这两次转换。这次转换不需要 switch
语句。
代码
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| class Program { static void Main(string[] args) { Console.Write("请输入序号:"); string no = Console.ReadLine();
Animal animal = AnimalFactory.GetAnimal(no); Console.WriteLine(AnimalSystem.Name(animal)); Console.WriteLine(AnimalSystem.Sound(animal));
Console.Read(); } }
class AnimalSystem { public static string Name(Animal animal) { return animal.Name(); }
public static string Sound(Animal animal) { return animal.Sound(); } }
class Animal { public virtual string Name() { return "这种情况是要加钱的!"; } public virtual string Sound() { return "这种情况是要加钱的!"; } }
class Cat : Animal { public override string Name() { return "名为猫咪"; }
public override string Sound() { return "叫了一声:喵喵喵?"; } }
class Frog : Animal { public override string Name() { return "名为青蛙"; }
public override string Sound() { return "叫了一声:蛤?"; } }
class AnimalFactory { public static Animal GetAnimal(string no) { switch (no) { case "1": return new Cat(); break; case "2": return new Frog(); break; default: return new Animal(); break; } } }
|
解析
通过引入 AnimalFactory
这个简单工厂,之后通过多态特性消除了多次的 switch
语句。如果需要添加新的类型如美羊羊,则需要修改3个地方。
- 新建类继承自
Animal
- 实现相应的
Name()
和 Sound()
方法
- 在工厂类
AnimalFactory
中添加新的 case
实际上就算是不了解简单工程模式也很可能写出来。设计模式应该是自然而然的应用而不是刻意地使用,产生冗余的代码。
总结
这个简单的例子还有很多可以优化的地方。例如 Animal
类应该是抽象类,不包含具体的实现。同时可以引入Null Class来用于输出 这种情况是要加钱的!等类似没有实现的情况下的默认行为。还可以将简单工厂模式改成工厂模式以符合开放-封闭原则。不过这些都不是本文范围内的。我学膜法去了。 :)