人们经常说到的工厂模式有三种:简单工厂模式,工厂方法模式和抽象工厂模式.
例如: 当你拥有一家包子铺时,每天早上你需要制作多种多样的包子来出售.这时我们创建的包子铺代码为:
/**
* @Description: 包子类
* @author: wangjie
* @createAt: 2018/8/19-09:56
*/
public class Bun {
private int size; // 大小
private int price; // 单价 分
private int type;// 类型, 馅
public void prepare(){
System.out.println("准备阶段,上屉等");
}
public void steamBun(){
System.out.println("蒸包子");
}
public void finish(){
System.out.println("蒸好出笼");
}
.....
}
/**
* @Description: 包子类型
* @author: wangjie
* @createAt: 2018/8/19-10:12
*/
public enum BunEnums {
CABBAGE_BUN(1,"白菜馅包子"),
LEEK_BUN(2,"韭菜馅包子"),
;
public int type ;
private String desc;
BunEnums( int type, String desc ) {
this.type = type;
this.desc = desc;
}
public int getType() {
return type;
}
public String getDesc() {
return desc;
}
}
/**
* @Description: 白菜馅包子
* @author: wangjie
* @createAt: 2018/8/19-10:09
*/
public class CabbageBun extends Bun {
// 制作白菜馅
}
/**
* @Description: 韭菜馅包子
* @author: wangjie
* @createAt: 2018/8/19-10:14
*/
public class LeekBun extends Bun {
//制作韭菜馅
}
/**
* @Description: 包子铺业务类
* @author: wangjie
* @createAt: 2018/8/19-10:01
*/
public class BunStoreService {
/**
* 1 下单,购买包子
* @param bunType
* @return
*/
public Bun orderBun(int bunType){
Bun bun = null;
if (BunEnums.CABBAGE_BUN.getType() == bunType){
bun = new CabbageBun();
}else if (BunEnums.LEEK_BUN.getType() == bunType){
bun = new LeekBun();
}
bun.prepare(); // 上屉
bun.steamBun();// 蒸
bun.finish(); // 完成,出笼
return bun;
}
}
当有人来购买包子时(假设为现场制作),包子铺根据他提供的类型来创建包子对象,并将它需要的包子对象返回.
随着包子铺的扩张,包子铺可能还提供猪肉馅,粉丝馅等其他馅包子.这时我们的BunEnums
需要扩展,BunStoreService.orderBun(int bunType)
需要修改.修改后代码如下:
/**
* @Description: 包子铺业务类
* @author: wangjie
* @createAt: 2018/8/19-10:01
*/
public class BunStoreService {
/**
* 1 下单,购买包子
* @param bunType
* @return
*/
public Bun orderBun(int bunType){
Bun bun = null;
if (BunEnums.CABBAGE_BUN.getType() == bunType){
bun = new CabbageBun();
}else if (BunEnums.LEEK_BUN.getType() == bunType){
bun = new LeekBun();
}
// do add by 汪杰 at 2018/8/19 10:35 Reason: 包子铺扩展,添加了包子类型
else if (BunEnums.PORK_BUN.getType() == bunType){
bun = new PorkBun();
}else if (BunEnums.RICE_NOODLES_BUN.getType() == bunType){
bun = new RiceNoodlesBun();
}
// do add end
bun.prepare(); // 上屉
bun.steamBun();// 蒸
bun.finish(); // 完成,出笼
return bun;
}
}
随着包子铺不断的扩张,包子类型不断添加,下单购买包子的业务代码需要不但的修改.
但是,事实上下单购买的流程是不变的,变动的是制作包子的过程.
我们知道了哪些是可变的,哪些是不变的,根据 对扩展开放,对修改关闭 的原则,将可变动的代码封装到一起.
我们可以使用一个新的对象,由它来负责创建包子对象,我们可以称这个新的对象为 “工厂”.
/**
* @Description: 简单工厂
* @author: wangjie
* @createAt: 2018/8/19-10:50
*/
public class SimpleBunfactory {
/**
* 创建包子对象
* @param bunType 包子类型
* @return bun
*/
public Bun createBun(int bunType){
Bun bun = null;
if (BunEnums.CABBAGE_BUN.getType() == bunType){
bun = new CabbageBun();
}else if (BunEnums.LEEK_BUN.getType() == bunType){
bun = new LeekBun();
}else if (BunEnums.PORK_BUN.getType() == bunType){
bun = new PorkBun();
}else if (BunEnums.RICE_NOODLES_BUN.getType() == bunType){
bun = new RiceNoodlesBun();
}
return bun;
}
/**
* 创建包子对象
*
* 利用静态方法定义一个工厂,这种方法很常见,经常被称为 静态工厂
* 优点: 在业务类中不需要实例化工厂对象就可以用来实例化对象
* 缺点: 不能通过继承来改变创建实例化的方法和行为.
*
* @param bunType 包子类型
* @return bun
*/
public static Bun createBunByType(int bunType){
Bun bun = null;
if (BunEnums.CABBAGE_BUN.getType() == bunType){
bun = new CabbageBun();
}else if (BunEnums.LEEK_BUN.getType() == bunType){
bun = new LeekBun();
}else if (BunEnums.PORK_BUN.getType() == bunType){
bun = new PorkBun();
}else if (BunEnums.RICE_NOODLES_BUN.getType() == bunType){
bun = new RiceNoodlesBun();
}
return bun;
}
}
包子铺的业务类改为
/**
* @Description: 包子铺业务类
* @author: wangjie
* @createAt: 2018/8/19-10:01
*/
public class BunStoreService {
SimpleBunfactory simpleBunfactory;
public BunStoreService(SimpleBunfactory simpleBunfactory){
this.simpleBunfactory = simpleBunfactory;
}
/**
* 1 下单,购买包子
* @param bunType
* @return
*/
public Bun orderBun(int bunType){
Bun bun = simpleBunfactory.createBun(bunType);
//Bun bun = SimpleBunfactory.createBunByType(bunType);
bun.prepare(); // 上屉
bun.steamBun();// 蒸
bun.finish(); // 完成,出笼
return bun;
}
}
此时.我们就已经完成了使用 “简单工厂模式” 来创建对象,
我们将创建包子对象的代码封装到了一个类,当以后包子铺的包子类型在扩展或某种包子下线时,就只需要修改这一个地方.
有人会觉得,之前在orderBun(int bunType)
方法中创建对象,当扩展时,也只需要修改一处,为什么还需要这么麻烦呢?
我们将集体的实例化包子对象的代码从下单流程中抽离出来,对扩展开发,对修改关闭
可能每一种包子都由指定的师傅制作.张师傅制作白菜馅包子,李师傅制作韭菜包子.这时整个包子厂就是一个父工厂类,张师傅/李师傅就是有两个子工厂类.
工厂类
/**
* 包子工厂
* @AUTHOR 汪杰
* @CREATE 2018/11/13 16:46
*/
public interface BunFactory {
T createBun();
}
/**
* @Description: 白菜包工厂
* @author: wangjie
* @createAt: 2019/3/28-22:22
*/
public class CabageBunFactory implements BunFactory {
@Override
public CabbageBun createBun() {
return new CabbageBun();
}
}
/**
* @Description: 韭菜包工厂
* @author: wangjie
* @createAt: 2019/3/28-22:22
*/
public class LeekBunFactory implements BunFactory {
@Override
public LeekBun createBun() {
return new LeekBun();
}
}
包子实体类
/**
* @Description: 包子
* @author: wangjie
* @createAt: 2019/3/28-22:54
*/
public interface Bun {
}
/**
* @Description: 包子类
* @author: wangjie
* @createAt: 2019/3/28-22:19
*/
public abstract class AbstractBun implements Bun ,Serializable{
public void prepare(){
System.out.println("准备阶段,上屉等");
}
public void steamBun(){
System.out.println("蒸包子");
}
public void finish(){
System.out.println("蒸好出笼");
}
}
/**
* @Description: 白菜馅包子
* @author: wangjie
* @createAt: 2018/8/19-10:09
*/
public class CabbageBun extends AbstractBun {
}
/**
* @Description: 韭菜馅包子
* @author: wangjie
* @createAt: 2018/8/19-10:14
*/
public class LeekBun extends AbstractBun {
}
当包子店的生意越来越好,两种口味的包子不能满足客户的需要时,老板可能就会引进新的口味的包子,新请一个王师傅制作猪肉馅包子.遇到这种情况,代码中只需要新建一个工厂和一个包子实例.
/**
* @Description: 猪肉馅包子工厂
* @author: wangjie
* @createAt: 2019/3/28-22:49
*/
public class PorkBunFactory implements BunFactory {
@Override
public PorkBun createBun() {
return new PorkBun();
}
}
/**
* @Description: 猪肉馅包子
* @author: wangjie
* @createAt: 2019/3/28-22:48
*/
public class PorkBun extends AbstractBun {
}
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题.