雷锋依然在人间—工厂方法模式

来源:互联网 发布:编程兼职怎么赚钱 编辑:程序博客网 时间:2024/05/18 23:13

定义

工厂方法(factory method):定义一个生成对象的接口,让子类来决定实例化那个类。工厂方法使一个类的实例化延迟到子类。

类图



工厂方法中分为抽象产品(Procuct)、具体产品(ConcreteProduct)、抽象工厂(Createor)、具体工厂(ConcreteCreator)。每一个具体的工厂用于生产一个具体的产品。具体的工厂依赖一个抽象产品,利用多态,可以在运行时返回具体的产品。

工厂方法 VS 简单工厂

我们通过一个计算器的实例来对比一下工厂方法和简单工厂。

简单工厂模式实现计算器UML图

工厂方法模式实现UML类图



工厂方法和简单工厂要实现的目的都是隐藏对象的实例化操作,让对象的实例化操作集中在一个地方,封装了对象的实例化,这样我们在更改实例化对象类型时改动的就相对较小。还有一个就是让客户端和具体的产品隔离,客户端只需要知道抽象产品即可,无需知道具体产品。

简单工厂

优点:除去了对具体产品的依赖,包含了必要的逻辑判读,简化了客户端的使用。原因是:简单工厂类中包含了必要的判断逻辑,根据客户端传入的条件动态实例化相关的类,返回的类型是抽象产品类(抽象的运算类),对于客户端来说去除了与具体产品的依赖,客户端只需要依赖抽象产品,不需要依赖具体产品。我们在客户端这样使用 简单工厂类.创建产品方法(type),type是"+"返回的加法运算对象,是"-"返回的减法运算对象,客户端并不需要知道“+”、“-”对应的是具体哪个类来实现的,客户端只需要做运算就可以,省去了客户端选择运算类的逻辑判断。

缺点:破坏了开放-关闭原则。原因是:如果我们需要添加一个"M的N次方的算法",我们需要添一个“M的N次方”类,然后修改简单工厂里逻辑判断,if(type.equals("M的N次方"))。也就是说对修改也开放了。ps:其实这个缺点可以通过反射技术来解决,所有使用简单工厂的地方都可以用反射技术来消除switch或if。

缺点:客户端在更改相应的具体产品时,相对工厂方法改动会大一些。

工厂方法

优点:很好的遵守了开放-关闭原则。要添加一个"M的N次方"的算法,我们只需要添加一个"M的N次方"的类,在添加一个"M的N次方"的工厂类,这个工厂类实现了抽象工厂,负责返回"M的N次方"的实例"。注意:每增加一个算法,就会增加两个类(一个具体的运算类和对应的工厂类),这样也增加了开发量和系统的复杂度。

优点:客户端在更改相应的具体产品时,相对简单工厂修改会小一些。怎么来理解呢?客户端使用简单工厂在100个地方调用了SimpleFactory.getResult("+")来获得加法预算,如果要把加法预算改成减法,需要改100个地方。如果客户端使用工厂方法在客户端调用了这两行代码来获得加法运算实例:
IFactory factory = new AddFactory(); Operation oper = factory.createOperation();//调用了100次这样的代码
这时我们需要把加法预算改成减法运算,只需要将 IFactory factory = new AddFactory(); 修改成 new SubFactory()即可。


缺点:客户端需要自行判断使用哪个算法工厂。如果客户端需要使用加法运算,就需要先实例化加法工厂,然后调用创建加法运算实例的方法,其它运算以此类推。如果新增加一个"求M的N次方的"运算,可客户端就要修改客户端代码来创建"M的N次方"的工厂实例来调用创建"M的N次方"运算的实例对象。也就是说工厂方法把简单工厂的逻辑判断从简单工厂移到了客户端。如果你想增加一个新的算法,简单工厂是修改简单工厂的代码,工厂方法是修改客户端的代码。

我们可以看出工厂方法和简单工厂的目标都是相同的,在实现的时候侧重点是不同的。从开闭原则来讲工厂方法完全遵守了,而简单工厂遵守的不是很好。从客户端的使用来讲工厂方法没有封装选择算法的逻辑,有新的算法加入需要修改客户端的选择算法的逻辑。而简单工厂将选择算法的逻辑封装在了内部,仅仅依赖一个简单工厂,简化了客户端的使用。简单工厂在增加新算法就修改简单工厂类,工厂方法是就该使用的客户端。
两种工厂方法各有适合使用的场合,请在分析清楚自己的问题和对两种工厂熟悉的情况下选择使用哪一种。我们可把工厂方法看做是简单工厂的进一步抽象和推广。

ps:个人的理解是大多数情况下简单工厂比工厂方法要更胜任对象的创建。简单工厂的缺点就是增加一种具体的产品,需要修改简单工厂的switch语句,增加case分支,而反射技术刚好可以解决这样的问题(反射技术+简单工厂)。

1 0
原创粉丝点击