5,工厂方法模式

1,前言

我们将简单工厂,工厂方法,抽象工厂三种模式(虽然简单工厂并不算是一种模式)列为一个工厂专题

前一篇介绍了简单工厂(可点击下边链接进入),它封装了创建具体对象的逻辑(变化的部分),
增加产皮或改变产品的实现,不需要修改客户端,将产品的"实现"从使用中"解耦",降低了代码耦合度

这篇我们说一下工厂方法模式,代码上继续延用简单工厂外卖快餐店各种饭的例子
工厂方法模式是在简单工厂基础上的进一步抽象

传送门 : 简单工厂


2,需求场景&技术实现

工厂方法Demo需求场景:

    餐厅可以做2种饭
        烤肉饭(番茄烤肉饭,沙拉烤肉饭)
        鸡肉饭(番茄鸡肉饭,沙拉鸡肉饭)

    每种饭食统一的制作步骤
        准备食材->加工烹饪->装盒摆放->打包外送

技术实现:

    创建抽象"饭"类,具有准备,烹饪,摆放,打包方法
    具体"饭"类继承抽象"饭"类,重写各个步骤的实现
    创建一个做饭的类(工厂),产生一个饭对象,并控制制作流程(准备食材->加工烹饪->装盒摆放->打包外送)

3,工厂方法模式

工厂方法模式:定义了一个创建对象的接口,由子类定实例化哪一个类
工厂方法将类的实例化延迟到子类

1)创建饭食工厂抽象类:

    创建饭食工厂抽象类
    封装"饭"对象的生产流程
    但将创建具体"饭"对象的过程交给子类决定
package com.brave.food.methodfactory.factory;

import com.brave.food.methodfactory.food.Rice;

/**
 * 食物工厂超类
 *  规定了食物生产流程的框架
 *  对于食物的创建过程由子类决定
 * 
 *  工厂方法模式:定义一个创建对象的接口
 * 
 * @author Brave
 *
 */
public abstract class RiceFactory {

    /**
     * 创建食物的流程框架
     *      type是String类型,在判断中容易写错导致匹配不上,建议写成枚举
     * @param type
     * @return
     */
    public Rice orderFood(String type){

        Rice food;

        food = createFood(type);

        System.out.println("-----------"+type+"----------");

        food.prepare();
        food.cook();
        food.set();
        food.box();

        return food;
    }

    /**
     * 创建具体食物由子类决定(创建食物的行为封装在子类中)
     *      也可以在超类中默认实现一种,子类中重写,这样就有了默认的创建逻辑
     * @param type
     * @return
     */
    protected abstract Rice createFood(String type);
}

2)创建鸡肉饭工厂类:

鸡肉饭工厂类,继承自饭食工厂抽象父类
决定具体"饭"对象的过程
package com.brave.food.methodfactory.factory;

import com.brave.food.methodfactory.food.SaladChickenRice;
import com.brave.food.methodfactory.food.TomatoChickenRice;
import com.brave.food.methodfactory.food.Rice;

/**
 * 饭工厂类
 *  继承了食物工厂接口
 *  封装"饭"对象的创建过程
 * @author Brave
 *
 */
public class ChickenRiceFactory extends RiceFactory {

    @Override
    public Rice createFood(String name) {

        Rice rice = null;

        if(name.equals("Salad")){
            rice = new SaladChickenRice();
        } else if(name.equals("Tomato")){
            rice = new TomatoChickenRice();
        }

        return rice;
    }

}

3)剩余部分代码:

各种饭的抽象类:

package com.brave.food.methodfactory.food;

/**
 * Rice:饭食抽象类
 *      各种饭食继承此抽象类
 * @author Brave
 *
 */
public abstract class Rice {

    // 准备
    public void prepare(){
        System.out.println("准备");
    }

    // 烹饪
    public void cook(){
        System.out.println("烹饪");
    }

    // 摆放
    public void set(){
        System.out.println("摆放");
    }

    // 打包
    public void box(){
        System.out.println("打包");
    }
}

继承自”饭”超类的番茄鸡肉饭&沙拉鸡肉饭:

package com.brave.food.methodfactory.food;

/**
 * 番茄鸡肉饭
 * @author Brave
 *
 */
public class TomatoChickenRice extends Rice {

    @Override
    public void prepare() {
        System.out.println("番茄鸡肉饭-准备");
    }

    @Override
    public void cook() {
        System.out.println("番茄鸡肉饭-烹饪");
    }

    @Override
    public void set() {
        System.out.println("番茄鸡肉饭-摆放");
    }

    @Override
    public void box() {
        System.out.println("番茄鸡肉饭-打包");
    }

}
package com.brave.food.methodfactory.food;

/**
 * 沙拉鸡肉饭
 * @author Brave
 *
 */
public class SaladChickenRice extends Rice {

    @Override
    public void prepare() {
        System.out.println("沙拉鸡肉饭-准备");
    }

    @Override
    public void cook() {
        System.out.println("沙拉鸡肉饭-烹饪");
    }

    @Override
    public void set() {
        System.out.println("沙拉鸡肉饭-摆放");
    }

    @Override
    public void box() {
        System.out.println("沙拉鸡肉饭-打包");
    }

}

客户端

package com.brave.food.methodfactory;

import com.brave.food.methodfactory.factory.RiceFactory;
import com.brave.food.methodfactory.factory.ChickenRiceFactory;

public class Client {

    public static void main(String[] args) {

        RiceFactory riceFactory = new ChickenRiceFactory();
        riceFactory.orderFood("Tomato");
        riceFactory.orderFood("Salad");

    }
}
因为是Demo,所以我们传入的类型是字符串类型,但是这样可以会因为赋值错误导致
无法匹配到对应的产品,所以正规的说我们应该使用枚举类型来确保这部分的正确性

4,工厂方法模式的优势与不足

分析一下上面工厂方法模式的代码

首先,创建了一个"饭"的超类RiceFactory
orderFood()方法:控制了各种饭的制作流程(准备,烹饪,摆放,打包的框架)
createFood()方法:抽象方法,由子类实现,从而将创建具体类的决定权交给子类

接下来,创建了鸡肉饭工厂ChickenRiceFactory继承自RiceFactory
重写了createFood()方法,在子类中进行具体类的实例化,达到封装对象创建过程的目的
换句话说,选择使用哪种子类,就决定了实际创建的产品是什么

所以,相比于简单工厂,两者都实现了封装对象的创建过程,
但工厂方法模式创建了一个框架,通过继承让子类决定如何实现
工厂方法模式,比简单工厂更加灵活富有弹性,是简单工厂的进一步抽象
但每增加一个产品(具体工厂),都要相应的增加子工厂,增加额外的开发量

将创建具体对象的过程封装起来,降低客户端和工厂的耦合性
使客户在实例化对象时,依赖于接口,而不是具体,针对接口编程,而非实现

依赖倒置原则:不能让高层组件依赖于低层组件,两者都应依赖于抽象
抽象工厂RiceFactory,"饭"的超类Rice,属于高层组件
依赖他们的具体工厂和具体饭类,属于底层组件

5,拓展新的工厂

按照上边的分析,在原有代码的基础上添加新的工厂-烤肉饭工厂,生产番茄烤肉饭,沙拉烤肉饭

烤肉饭工厂:
继承自饭食抽象工厂,在子类中决定实例化具体对象的过程


package com.brave.food.methodfactory.factory;

import com.brave.food.methodfactory.food.Rice;
import com.brave.food.methodfactory.food.SaladBarbecueRice;
import com.brave.food.methodfactory.food.TomatoBarbecueRice;

/**
 * 面工厂类
 *  实现食物工厂接口
 *  封装"面"对象的创建过程
 * @author Brave
 *
 */
public class BarbecueRiceFactory extends RiceFactory {

    @Override
    public Rice createFood(String name) {

        Rice rice = null;

         if(name.equals("Salad")){
            rice = new SaladBarbecueRice();
        } else if(name.equals("Tomato")){
            rice = new TomatoBarbecueRice();
        }

        return rice;
    }

}

两种饭的具体对象:
继承自”饭”食抽象类

package com.brave.food.methodfactory.food;

/**
 * 番茄烤肉饭
 * @author Brave
 *
 */
public class TomatoBarbecueRice extends Rice {

    @Override
    public void prepare() {
        System.out.println("番茄烤肉饭-准备");
    }

    @Override
    public void cook() {
        System.out.println("番茄烤肉饭-烹饪");
    }

    @Override
    public void set() {
        System.out.println("番茄烤肉饭-摆放");
    }

    @Override
    public void box() {
        System.out.println("番茄烤肉饭-打包");
    }

}
package com.brave.food.methodfactory.food;

/**
 * 沙拉烤肉饭
 * @author Brave
 *
 */
public class SaladBarbecueRice extends Rice {

    @Override
    public void prepare() {
        System.out.println("沙拉烤肉饭-准备");
    }

    @Override
    public void cook() {
        System.out.println("沙拉烤肉饭-烹饪");
    }

    @Override
    public void set() {
        System.out.println("沙拉烤肉饭-摆放");
    }

    @Override
    public void box() {
        System.out.println("沙拉烤肉饭-打包");
    }

}

添加客户端的调用:

package com.brave.food.methodfactory;

import com.brave.food.methodfactory.factory.RiceFactory;    
import com.brave.food.methodfactory.factory.BarbecueRiceFactory;
import com.brave.food.methodfactory.factory.ChickenRiceFactory;

public class Client {

    public static void main(String[] args) {

        RiceFactory riceFactory = new ChickenRiceFactory();
        riceFactory.orderFood("Tomato");
        riceFactory.orderFood("Salad");

        riceFactory = new BarbecueRiceFactory();
        riceFactory.orderFood("Tomato");
        riceFactory.orderFood("Salad");
    }
}

输出:

-----------Tomato----------
番茄鸡肉饭-准备
番茄鸡肉饭-烹饪
番茄鸡肉饭-摆放
番茄鸡肉饭-打包
-----------Salad----------
沙拉鸡肉饭-准备
沙拉鸡肉饭-烹饪
沙拉鸡肉饭-摆放
沙拉鸡肉饭-打包
-----------Tomato----------
番茄烤肉饭-准备
番茄烤肉饭-烹饪
番茄烤肉饭-摆放
番茄烤肉饭-打包
-----------Salad----------
沙拉烤肉饭-准备
沙拉烤肉饭-烹饪
沙拉烤肉饭-摆放
沙拉烤肉饭-打包
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BraveWangDev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值