【设计模式】第五篇 - 工厂方法模式
发布于: 刚刚
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----------
沙拉烤肉饭-准备
沙拉烤肉饭-烹饪
沙拉烤肉饭-摆放
沙拉烤肉饭-打包
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 2
Brave
关注
还未添加个人签名 2018.12.13 加入
还未添加个人简介
评论