工厂方法设计模式
介绍
定义:工厂方法(Factory Method)模式的意义是定义一个创建产品工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
就是说原来简单工厂设计模式产品的创建必须要核心的一个工厂类来完成,现在把工厂类定义成一个接口,根据产品的需要我们创建具体的工厂类来继承这个核心工厂类,让具体的工厂类来创建产品。这样在要增加新的产品的时候我们只需要增加工厂类而不是改变工厂类。符合开闭原则。
优点:
1.仍然具有简单工厂的优点,服务器端修改了具体产品的类名以后,客户端不知道。
2.当客户端需要扩展一个新的产品,不需要修改作者原来的代码,只是扩展一个新的工厂而已,符合开闭原则。
缺点:
每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量,如果产品的种类过多就会导致工厂类的数量庞大。
总结:
工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。它们都是集中封装了对象的创建,在对象时,不需要做大的改动就可实现,降低了客户程序与产品对象的耦合。工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量,如果产品的种类过多就会导致工厂类的数量庞大。

图片来源:《大话设计模式》
例子
package designPattern.com.design.factorymethod;
public class Demo1 {
public static void main(String[] args) {
FoodFactory factory = new RiceFactory();
Food f = factory.Manufacture();
f.getFood();
}
}
//首先两个抽象类,一个工厂抽象类,一个是食物抽象类,每一个工厂抽象类对应为一个或一种食物类服务
abstract class FoodFactory { // 创建抽象的食物工厂
public abstract Food Manufacture();
}
abstract class Food { // 创建抽象的食物类
public abstract void getFood();
}
class RiceFactory extends FoodFactory { // 具体的工厂类为具体的产品服务
@Override
public Food Manufacture() {
return new Rice();
} // 创建具体的工厂类
}
class Rice extends Food {
@Override
public void getFood() {
System.out.println("得到米饭");
}
}
这其实就是工厂方法模式和简单工厂的区别所在。简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖,但是以上面为例我们需要增加一种生产面条的方法,那么就需要改动原来的工厂类,这个就违反了开闭原则,工厂方法模式通过把原来单一的一个工厂拆成多个工厂,这样我们在添加面条这种食物的时候只需要添加对应工厂并没有改变原来的类。
还有两个问题
问题1:
简单工厂,工厂方法都有一个优点,就是服务器端的具体产品类名变化了以后,客户端不知道,但是,看我们现在的代码,客户端仍然依赖于具体的工厂的类名,如果服务器端修改累具体的类名,又回到最初的起点。
解释:
工厂的名字,可以看做接口,对于接口作者有责任有义务,保证工厂的名字是稳定的,也就是说,虽然客户端依赖于工厂的具体的类名,可是所有的工厂名字都趋于稳定(不是百分百不变)至少工厂类的名字,要比具体产品的名字更加稳定,我们原来在原来产品的基础上在包装一层工厂就是希望变化发生在工厂内部(产品),而工厂本身对外提供的接口是不变的。
问题2:
既然添加的类是客户端自己添加的,为什么还要借助于工厂,不自己实例化呢。
解释:
产品的一些功能的实现是需要依赖于工厂类的,就是说可能原来作者实现的关于food类的方法是需要产品先被工厂包装再作为参数传入方法中,如果我们自己实例化这个类那么在调用对应方法的时候回导致传入的参数类型不匹配。