目录
1、需求
和简单工厂模式中的需求类似,需求内容增加。
一个牛奶项目:
- 牛奶有很多种:蒙牛甜牛奶(MengniuSweetMilk)、蒙牛酸牛奶(MengniuSourMilk)、伊利甜牛奶(ErieSweetMilk)、伊利酸牛奶(ErieSourMilk)等。
- 制作牛奶有:准备鲜牛奶(prepareMilk)、高温杀菌(pasteurize)、打包装(package)。
- 在高温杀菌的步骤可以加入不同的配料制作不同的牛奶。
- 编程完成牛奶订购功能。
需求分析:
- 使用简单工厂模式,创建不同的简单工厂类,比如MengniuFactory、ErieFactory等等,从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好。(简单工厂模式更适用于工厂类负责创建的对象比较少的场景)。
- 所以要使用工厂方法模式
2、工厂方法模式
2.1、基本介绍
- 工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
- 工厂方法模式设计方案:将牛奶项目的实例化功能抽象成抽象方法,在不同的牛奶子类中具体实现。
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
2.2、使用共厂方法模式解决需求
2.2.1、类图
2.2.2、代码
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
//创建蒙牛牛奶工厂
MengniuMilkFactory mengniuMilkFactory = new MengniuMilkFactory();
//创建伊利牛奶工厂
ErieMilkFactory erieMilkFactory = new ErieMilkFactory();
new Order(mengniuMilkFactory,"sweet","sour");
new Order(erieMilkFactory,"sweet");
}
}
/**
* 牛奶抽象类
*/
abstract class Milk{
private String name;
public void prepareMilk(){
System.out.println("准备新鲜的牛奶");
}
/**
* 高温杀菌
*/
public abstract void pasteurize();
public void packaging(){
System.out.println("将"+name+"打包装");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 蒙牛甜牛奶
*/
class MengniuSweetMilk extends Milk {
/**
* 高温杀菌
*/
@Override
public void pasteurize() {
System.out.println("高温杀菌,加入糖");
}
}
/**
* 蒙牛酸牛奶
*/
class MengniuSoutMilk extends Milk {
/**
* 高温杀菌
*/
@Override
public void pasteurize() {
System.out.println("高温杀菌,加入果酸");
}
}
/**
* 伊利甜牛奶
*/
class ErieSweetMilk extends Milk {
/**
* 高温杀菌
*/
@Override
public void pasteurize() {
System.out.println("高温杀菌,加入糖");
}
}
/**
* 伊利酸牛奶
*/
class ErieSoutMilk extends Milk {
/**
* 高温杀菌
*/
@Override
public void pasteurize() {
System.out.println("高温杀菌,加入果酸");
}
}
/**
* 牛奶工厂类
*/
abstract class MilkFactory{
/**
* 创建牛奶对象 具体实现推迟到子类
*/
public abstract Milk createMilk(String type);
}
/**
* 蒙牛牛奶工厂类
*/
class MengniuMilkFactory extends MilkFactory{
/**
* 创建牛奶对象 具体实现推迟到子类
*/
@Override
public Milk createMilk(String type) {
Milk milk = null;
if("sweet".equals(type)){
milk = new MengniuSweetMilk();
milk.setName("【蒙牛】甜牛奶");
}else if("sour".equals(type)){
milk = new MengniuSoutMilk();
milk.setName("【蒙牛】酸牛奶");
}
return milk;
}
}
/**
* 伊利牛奶工厂类
*/
class ErieMilkFactory extends MilkFactory{
/**
* 创建牛奶对象 具体实现推迟到子类
*/
@Override
public Milk createMilk(String type) {
Milk milk = null;
if("sweet".equals(type)){
milk = new ErieSweetMilk();
milk.setName("【伊利】甜牛奶");
}else if("sour".equals(type)){
milk = new ErieSoutMilk();
milk.setName("【伊利】酸牛奶");
}
return milk;
}
}
/**
* 订单类
*/
class Order{
private MilkFactory milkFactory;
public Order(MilkFactory milkFactory,String...types){
this.milkFactory = milkFactory;
for(String type:types){
//从工厂中获取牛奶对象
Milk milk = milkFactory.createMilk(type);
//输出牛奶制作过程
System.out.println("---------------"+milk.getName()+"制作过程------------");
milk.prepareMilk();
milk.pasteurize();
milk.packaging();
System.out.println();
}
}
}
运行结果:
2.2.3、总结
创建一个工厂抽象层,具体的实现代码交给子类去实现,这样使代码变得更灵活,且扩展性非常好,更弥补了简单工厂模式的不足。
3、应用场景
- 第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
- 第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。