一、介绍
工厂方法模式 Factory Method Pattern,属于创建型模式。
定义一个用于创建对象的接口,让子类决定实例化哪个产品类型对象。
工厂方法是一个产品类的实例化过程 延迟到其工厂的子类。
二、工厂方法模式原理
工厂方法模式的目的很简单,就是封装对象创建的过程,提升创建对象方法的
可复用性,只要是创建对象的地方都可以用工厂方法模式替代创建对象的过程。
工厂方法模式的主要角色:
1)抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂
方法来创建产品
2)具体工厂:主要实现抽象工厂中的抽象方法,完成具体产品的创建。
3)抽象产品:定义了产品的规范,描述产品的主要特性和功能。
4)具体产品:实现了抽象产品所定义的接口,由具体工厂来创建具体产品对象,
具体产品同具体工厂之间一一对应,工厂方法就没必要传参数了。
工厂方法UML图:
三、工厂方法模式优缺点
1、有点
1)用户只需要知道知道具体工厂,就可以获取想要的产品,不需要关注
产品的创建过程。
2) 在系统增加新产品的时候,只需要添加具体产品类及对应的具体工厂,
不需要对原工厂进行修改,满足了“开闭原则”
2、缺点
1)每增加一个产品,就需要新增具体的产品类及具体的工厂方法,这样
会增加系统的复杂度
四、工厂方法模式使用场景
例如:使用工厂方法模式对“简单工厂模式” 中的代码进行重构
3.1)使用工厂方法模式实现“模拟奖品发放”的UML图如下:
3.2)代码如下:
产品代码
/**
* 奖品发送接口
*/
public interface IFreeGoods {
ResponseResult sendGoods(AwardInfo award);
}
/*******************************************************
*
* 发放打折卷
*
*******************************************************/
public class DiscountFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendGoods(AwardInfo award) {
String uid = award.getUid();
String awardNumber = award.getAwardNumber();
return new ResponseResult("200","给用户 "+uid+"发送打折卷成功 "+awardNumber);
}
}
/*******************************************************
*
* 发送小礼品
*
*******************************************************/
public class SmallGifFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendGoods(AwardInfo award) {
SmallGiftInfo smallGiftInfo = new SmallGiftInfo();
smallGiftInfo.setUserName(award.getExtMap().get("username"));
smallGiftInfo.setPhone(award.getExtMap().get("phone"));
smallGiftInfo.setAddress(award.getExtMap().get("address"));
smallGiftInfo.setOrderId(UUID.randomUUID().toString());
System.out.println("小礼品发送成功,请注意查收!");
return new ResponseResult("200","小礼品发送成功",smallGiftInfo);
}
}
/*******************************************************
*
* 发送优酷会员
*
*******************************************************/
public class YouKuMemberFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendGoods(AwardInfo award) {
String phone = award.getExtMap().get("phone");
System.out.println("发放优酷会员成功。绑定手机号:"+phone);
return new ResponseResult("200","发放优酷会员成功。绑定手机号:"+phone);
}
}
工厂代码
/**
* 抽象工厂
*/
public interface FreeGoodsFactory {
public IFreeGoods getInstance();
}
/*******************************************************
* 具体工厂
* 用于创建 发放打折卷 对象
*******************************************************/
public class DiscountFreeGoodsFactory implements FreeGoodsFactory{
@Override
public IFreeGoods getInstance() {
return new DiscountFreeGoods();
}
}
/*******************************************************
*
* 具体工厂,用于创建 发放小礼品对象
*******************************************************/
public class SmallGifFreeGoodsFactory implements FreeGoodsFactory{
@Override
public IFreeGoods getInstance() {
return new SmallGifFreeGoods();
}
}
/*******************************************************
* 具体工厂,用于创建 优酷会员奖品对象
*******************************************************/
public class YouKuMemberFreeGoodsFactory implements FreeGoodsFactory{
@Override
public IFreeGoods getInstance() {
return new YouKuMemberFreeGoods();
}
}
客户端代码
/*******************************************************
* Client
*
*******************************************************/
public class DeliverController {
public ResponseResult awardToUser(AwardInfo awardInfo){
FreeGoodsFactory factory = null;
if(awardInfo.getAwardTypes() == 1){
factory = new DiscountFreeGoodsFactory();
}else if(awardInfo.getAwardTypes() == 2){
factory = new YouKuMemberFreeGoodsFactory();
}else if(awardInfo.getAwardTypes() == 3){
factory = new SmallGifFreeGoodsFactory();
}
IFreeGoods freeGoods = factory.getInstance();
ResponseResult responseResult = freeGoods.sendGoods(awardInfo);
return responseResult;
}
}
五、对工厂模式进一步优化
观察上边工厂模式重构的发送奖品代码发现,当有新的产品增加时,还是需要修改业务代码
的,这就破坏了“开闭原则”;针对这种情况我们可以创建一个工厂缓冲池的方式来优化
工厂方法,代码如下:
/*******************************************************
*
* 优化工厂方法:
* 创建工厂缓冲池,当产品增加时,只需要向工厂池中增加新的工厂实例,
* 不需要修改代码
*******************************************************/
public class FreeGoodsFactoryCollection {
private static final Map<Integer,FreeGoodsFactory> FACTORY_POOL = new HashMap<>();
//
static {
FACTORY_POOL.put(1,new DiscountFreeGoodsFactory());
FACTORY_POOL.put(2,new YouKuMemberFreeGoodsFactory());
FACTORY_POOL.put(1,new SmallGifFreeGoodsFactory());
}
/**
* 客户端获取工厂的方法
*
* @param type
* @return
*/
public static FreeGoodsFactory getFactory(Integer type){
return FACTORY_POOL.get(type);
}
}
客户端调用如下:
public class DeliverController {
public ResponseResult awardToUser(AwardInfo awardInfo){
FreeGoodsFactory factory = FreeGoodsFactoryCollection.getFactory(awardInfo.getAwardTypes());
IFreeGoods freeGoods = factory.getInstance();
ResponseResult responseResult = freeGoods.sendGoods(awardInfo);
return responseResult;
}
}