前言
之前的博客介绍了简单工厂,虽然简单工厂达到了工厂模式的效果,但是简单工厂在设计上却有很大的缺陷,其中最大的缺点就是不易扩展,而在工厂方法模式里则修正了这个缺点,下面举例的程序是从简单工厂改的,简单工厂是了解工厂模式的入门,建议先去看看我写的简单工厂的博客。
传送门:https://blog.csdn.net/zhen921/article/details/81986986
实例引入
情景依然是做饭,只不过为了让程序容易理解,这次删掉了菜单的饺子类,只剩下大米和面条,而工厂改为了抽象,增加了两个子工厂分别做两种饭(改动相当于之前一个厨子做所有的饭,现在明确分工,每个厨子只做一种饭),话不多说,先看类图和例子,再做分析。
程序类图
Java源程序如下
菜单类(未改动)
package factorymethod_06;
public interface Menu {
public void getMeal();//只定义取饭的方法
}
面条类(未改动)
package factorymethod_06;
public class Noodles implements Menu{
public void getMeal() {//拿到面条
System.out.println("面条");
}
}
米饭类(未改动)
package factorymethod_06;
public class Rice implements Menu{
public void getMeal() {
System.out.println("大米");
}
}
抽象工厂类
package factorymethod_06;
public abstract class FoodFactory {
public abstract Menu getFood();//只定义获取对象的方法
}
米饭工厂(新增类)
package factorymethod_06;
public class RiceFactory extends FoodFactory{
public Menu getFood() {
return new Rice();//返回米饭实例
}
}
面条工厂(新增类)
package factorymethod_06;
public class NoodlesFactory extends FoodFactory{
public Menu getFood() {
return new Noodles();//返回面条实例
}
}
客户端
package factorymethod_06;
public class Client {
public static void main(String[] args) {
FoodFactory ff=new RiceFactory();
Menu rice= ff.getFood();//获取米饭实例
rice.getMeal();
}
}
测试结果
实例分析(重在理解)
之前的简单工厂是集成了所有实例的创建逻辑,这样完成了我们的目标,即需要对象就去找工厂拿,而缺陷就在于如果添加一个新的类,比如有一个做蛋炒饭的类,我就不得不再次修改工厂类,让工厂能创建蛋炒饭的对象,这样程序就没有什么弹性,而在本例中把工厂的职责进一步的切割,把他作为抽象类提炼出来,下面设立米饭工厂和面条工厂,分别负责做米饭和面条,这样如果我们在添加蛋炒饭类,作文只需要照葫芦画瓢,新建一个蛋炒饭工厂就行了,这样扩展菜单就会变得很轻松,而且不用改动原有的代码。
既然知道了工厂模式的作用,那下面我们就来总结一下他有哪些特点。
定义
定义一个创建对象的接口,但由子类决定实例化的类是哪一个。工厂方法把类的实例化推迟到了子类
使用场景
需要一个产品(对象)而不关心产品是怎么创建的,例如sessionfactory,只知道它能获取session就足够了
用到的设计原则
-
- 开闭原则
优点
- 可以容易添加新的种类而不用更改原有的代码,完美的诠释了开闭原则的应用
- 用户想要拿到产品不用关心是怎么做出来的
缺点
-
- 每添加一个种类就要写一个具体工厂和具体产品,类越多,越复杂
- 不可以对同类产品进行扩展,例如想把面条分为大碗小碗,工厂方法就没法在不违反开闭原则的基础上进行扩展了(这是抽象工厂能做的)
角色组成
由类图可以看出,主要角色有四种
抽象产品 | 定义工厂方法所创建的对象 |
具体产品 | 继承抽象产品的具体产品 |
抽象工厂 | 声明创建对象的方法,返回一个产品类型的对象 |
具体工厂 | 实现创建具体产品的方法,并返回具体产品对象 |
写在后面
下篇博客,我会继续扩展这个例子,让产品可以扩展它的家族,也就是让工厂可以生产大份或者小份的面条和米饭,也就是抽象工厂模式所做的事