工厂模式在应用中使用得也很广泛,他提供了一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
考虑一个动物类Animal,提供shout,eate,grow方法,并从这个抽象类派生具体的动物子类:Cow,Horse,Dog,Pig
最后通过Factory类实例化他们,Factory提供一个静态的方法getAnimalInstance,并传递一个字符串参数表示创建具体的
类
下面是java实现的代码例子:
import java.util.*; interface Animal{ // 动物在叫 public void shout(); // 动物在吃 public void eate(); // 动物在生长 public void grow(); } class Cow implements Animal{ public void shout(){ System.out.println("牛在哞哞叫"); } public void eate(){ System.out.println("牛在吃草"); } public void grow(){ System.out.println("牛在生长"); } } class Horse implements Animal{ public void shout(){ System.out.println("马在嘶鸣"); } public void eate(){ System.out.println("马在吃草"); } public void grow(){ System.out.println("马在生长"); } } class Pig implements Animal{ public void shout(){ System.out.println("猪在叫"); } public void eate(){ System.out.println("猪在吃食物"); } public void grow(){ System.out.println("猪在生长"); } } class Dog implements Animal{ public void shout(){ System.out.println("狗在汪汪叫"); } public void eate(){ System.out.println("狗在吃骨头"); } public void grow(){ System.out.println("狗在生长"); } } class Factory{ public static Animal getAnimalInstance(String type){ Animal an=null; if (type.equals("Dog")){ an = new Dog(); } else if (type.equals("Cow")){ an = new Cow(); } else if (type.equals("Horse")){ an = new Horse(); } else if (type.equals("Pig")){ an = new Pig(); } else{ System.out.println("没发现这个类型"); System.exit(1); } return an; } } public class FactoryDemo01 { public static void main(String[] args) { if (args.length<=0){ System.out.println("必须输入一个命令行参数"); System.exit(1); } Animal an = Factory.getAnimalInstance(args[0]); an.shout(); an.eate(); an.grow(); } }
从上面的代码可以看到,要从工厂里生成一个具体的动物对象,只需向工厂的getAnimalInstance传递一个字符串参数即可
但是我们仔细再看一下Factory类的getAnimalInstance方法,当我们再派生一个Elephant 大象类时,我们又不得不以修改
Factory里的if - else 逻辑为代价!
兴奋的是java语言中提供的Class类的一个forName可以从一个字符串生成对应的类实例的能力,而C++是没有这个本事的,原因是java是解析执行的,而C++是编译型的语言,c++中怎么实现类似的功能呢?在以后的文章中再描述。
好了我们继续改进上面的代码,主要是改进Factory类的实现
class Factory{ public static Animal getAnimalInstance(String type){ Animal an=null; /**if (type.equals("Dog")){ an = new Dog(); } else if (type.equals("Cow")){ an = new Cow(); } else if (type.equals("Horse")){ an = new Horse(); } else if (type.equals("Pig")){ an = new Pig(); } else{ System.out.println("没发现这个类型"); System.exit(1); }*/ try{ an = (Animal)Class.forName(type).newInstance(); } catch(Exception e){ System.out.println("没发现这个类型"); System.exit(1); } return an; } }
好了,在命令行里输入Dog,然后执行:
狗在汪汪叫
狗在吃骨头
狗在生长
好,这回解决了由于增加子类而不得不修改工厂的问题,在我们看来貌似已经十分的完美了,工厂模式做到这个程度总可以了吧?
别急,新的问题又产生了,客户的需求总是不断的改,功能不断的加,我们的子类不断的膨胀,子类越来越多,客户使用我们的工厂类时
对具体的子类比较难记,这时我们可以通过使用一个代号到具体的子类映射来解决这个问题,java中为我们提供了Properties这样的一个类
实际上这个类就是从我们的hashtable类派生而来的。
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
具体的改进代码我就不贴出来了,使用Properties后我们可以从xml之类的文件加载准备创建的类信息然后生成对应的类实例,
客户只需修改xml文件就可,方便至极@!