一、介绍

        工厂方法模式 Factory Method Pattern,属于创建型模式。

        定义一个用于创建对象的接口,让子类决定实例化哪个产品类型对象。

         工厂方法是一个产品类的实例化过程 延迟到其工厂的子类。

       

二、工厂方法模式原理

        工厂方法模式的目的很简单,就是封装对象创建的过程,提升创建对象方法的

        可复用性,只要是创建对象的地方都可以用工厂方法模式替代创建对象的过程。

        工厂方法模式的主要角色:

               1)抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂

                                       方法来创建产品

               2)具体工厂:主要实现抽象工厂中的抽象方法,完成具体产品的创建。

               3)抽象产品:定义了产品的规范,描述产品的主要特性和功能。

               4)具体产品:实现了抽象产品所定义的接口,由具体工厂来创建具体产品对象,

                                       具体产品同具体工厂之间一一对应,工厂方法就没必要传参数了。

          工厂方法UML图:

          设计模式之工厂方法模式-LMLPHP

三、工厂方法模式优缺点

        1、有点

                 1)用户只需要知道知道具体工厂,就可以获取想要的产品,不需要关注

                       产品的创建过程。

                 2) 在系统增加新产品的时候,只需要添加具体产品类及对应的具体工厂,

                       不需要对原工厂进行修改,满足了“开闭原则”

         2、缺点

                 1)每增加一个产品,就需要新增具体的产品类及具体的工厂方法,这样

                      会增加系统的复杂度

四、工厂方法模式使用场景

        例如:使用工厂方法模式对“简单工厂模式” 中的代码进行重构

        3.1)使用工厂方法模式实现“模拟奖品发放”的UML图如下:

                设计模式之工厂方法模式-LMLPHP

       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;
    }
}
04-07 05:57