写点什么

【设计模式】第五篇 - 工厂方法模式

用户头像
Brave
关注
发布于: 刚刚

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,工厂方法模式的优势与不足

分析一下上面工厂方法模式的代码
首先,创建了一个"饭"的超类RiceFactoryorderFood()方法:控制了各种饭的制作流程(准备,烹饪,摆放,打包的框架)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----------沙拉烤肉饭-准备沙拉烤肉饭-烹饪沙拉烤肉饭-摆放沙拉烤肉饭-打包
复制代码


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【设计模式】第五篇 - 工厂方法模式