在软件开发过程中,我们不希望将我们的具体实现暴露给调用方,所以我们就要利用接口对我们的实现进行封装,下面举一个例子说明:
图1 类与接口关系类图
图1中的Product1和Product2都实现IProduct这个接口,这样,对于调用方来说,它一直都是对IProduct进行操作,具体实现的方法到底是Product1的还是Product2的,调用方不需要知道,具体代码如下:
IProduct product = new Product1(); ( 或 IProduct product = new product2(); )
product.sayMethod();
但是,我们可以看到当我们实例化的时候,还是用到了Product1或者Product2,这不是我们想要看到的,所以我们要设法将Product1和Product2也“隐藏”起来,那么我们就要对实例化过程进行封装,用一个类来做实例化的工作,这时候,简单工厂模式就出现了:
图2 简单工厂模式类图
图2中的ProductFactory类的createInstance方法对IProduct的实例化进行了封装,这样对于Client来说,它只能开到IProduct和ProductFactory,利用ProductFactory的createInstance方法将IProduct返回给Client,从而达到了对具体实现的完全封装。
这时候我们发现,有多少在createInstance方法中对实例化具体实现类的判断是用ifelse实现的,也就是说,如果有很多个Product,就要有相同数量的条件判断,这种情况我们忍一忍可以接受。但是这时临时需要增加一个Product,这就糟糕了,难道我们要改ProductFactory吗?如果以后再增加怎么办?不断的修改和编译ProductFactory吗?这是我们无论如何都不可能接受的,那么我们就要将这部分“死代码”救活,这时我们想到了反射,利用反射机制,通过产品类的名称从RunTime中找到它并将其实例化,而产品类的名称我们把它放到一个xml里边,为每一个产品类定义一个关键字,这样我们就把这部分“死代码”救活了!
图3 进行优化后的简单工厂类图
在程序初始化的时候调用XmlHandler类中的initXmlMap方法读取xml,封装到Map里。当ProductFactory进行产品类实例化的时候,通过调用XmlHandler类的getClassName方法取得具体产品类的类名,然后利用反射对产品类进行实例化。