Skip to content
CodingDiary
返回

设计模式之创建型设计模式-工厂方法模式

编辑页面
导读

简单工厂的 if-else 越写越长?工厂方法模式来解耦!核心思想:把具体类的实例化延迟到工厂子类,新增产品只需新增工厂类,不用改原有代码。本文继续用糖果工厂的例子,对比简单工厂 vs 工厂方法的 UML 图和代码实现。附 JDK Calendar.getInstance() 源码分析,看看大佬怎么用。

1. 模式简介

工厂方法模式(Factory Method Pattern):又称为工厂模式,属于创建型设计模式。在工厂方法模式中,工厂父类负责定义创建对象的公共接口,工厂子类负责生成具体的对象,这样做的目的是将具体类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体对象。本文将使用 糖果工厂生产不同口味的糖果 这个实际场景,用代码来实现 工厂方法模式

2. 模式角色

工厂方法模式包含以下4种角色:

  1. 抽象实体(Candy):糖果类基类
  2. 具体实体实现(LemonCandyWatermelonCandy):具体口味糖果实现
  3. 抽象工厂(CandyFactory):糖果工厂类基类
  4. 具体工厂实现(LemonCandyFactoryWatermelonCandyFactory):具体口味糖果工厂类实现

3. UML图例

4. 代码实现

4.1. 步骤一:创建抽象糖果类

Candy.java

/**
 * <p>
 * 糖果抽象类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod
 * @description: 糖果抽象类
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 11:28
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public abstract class Candy {

    /**
     * 口味
     */
    public abstract void taste();
}

4.2. 步骤二:创建抽象糖果工厂类

CandyFactory.java

/**
 * <p>
 * 糖果工厂抽象类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod
 * @description: 糖果工厂抽象类
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 11:29
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public abstract class CandyFactory {
    /**
     * 生产糖果
     *
     * @return 对应口味的糖果
     */
    public abstract Candy produceCandy();
}

4.3. 步骤三:创建具体的不同口味的糖果类

LemonCandy.java

/**
 * <p>
 * 柠檬味糖果
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod
 * @description: 柠檬味糖果
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 11:28
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class LemonCandy extends Candy {
    /**
     * 口味
     */
    @Override
    public void taste() {
        System.out.println("柠檬味");
    }
}

WatermelonCandy.java

/**
 * <p>
 * 西瓜味糖果
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod
 * @description: 西瓜味糖果
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 11:28
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class WatermelonCandy extends Candy {
    /**
     * 口味
     */
    @Override
    public void taste() {
        System.out.println("西瓜味");
    }
}

4.4. 步骤四:创建具体的不同口味的糖果工厂类

LemonCandyFactory.java

/**
 * <p>
 * 柠檬味糖果工厂类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod
 * @description: 柠檬味糖果工厂类
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 11:30
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class LemonCandyFactory extends CandyFactory {
    /**
     * 生产柠檬味糖果
     *
     * @return 柠檬味糖果
     */
    @Override
    public Candy produceCandy() {
        return new LemonCandy();
    }
}

WatermelonCandyFactory.java

/**
 * <p>
 * 西瓜味糖果工厂类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod
 * @description: 西瓜味糖果工厂类
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 11:30
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class WatermelonCandyFactory extends CandyFactory {
    /**
     * 生产西瓜味糖果
     *
     * @return 西瓜味糖果
     */
    @Override
    public Candy produceCandy() {
        return new WatermelonCandy();
    }
}

4.5. 步骤五: 测试

PatternTest.java

import com.xkcoding.design.pattern.creational.factorymethod.Candy;
import com.xkcoding.design.pattern.creational.factorymethod.CandyFactory;
import com.xkcoding.design.pattern.creational.factorymethod.LemonCandyFactory;
import com.xkcoding.design.pattern.creational.factorymethod.WatermelonCandyFactory;

/**
 * <p>
 * 工厂方法模式测试类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.factorymethod.run
 * @description: 工厂方法模式测试类
 * @author: yangkai.shen
 * @date: Created in 2019-02-14 14:54
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class PatternTest {
    public static void main(String[] args) {
        CandyFactory factory1 = new LemonCandyFactory();
        Candy candy1 = factory1.produceCandy();
        candy1.taste();

        CandyFactory factory2 = new WatermelonCandyFactory();
        Candy candy2 = factory2.produceCandy();
        candy2.taste();
    }
}

5. 应用

// JDK中的应用
// 获取日历对象 -> Calendar.getInstance() -> createCalendar(TimeZone zone,Locale aLocale)

6. 场景

7. 优缺点

优点: 以本例为例,1、扩展性高,如果想增加一个具体口味的糖果,只需要添加具体口味的糖果实现,同时添加具体口味的糖果工厂即可。2、屏蔽糖果的具体实现,调用方只关心抽象实体的通用接口在具体口味糖果类中的不同实现。

缺点: 以本例为例,每增加一种糖果口味,都需要增加一种具体的实现类,同时增加具体的工厂类,如果系统中存在很多不同口味的糖果,则会导致类的数量成倍增加,增加了系统的复杂度。

8. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/creational/factorymethod


编辑页面
分享到:

上一篇
使用Mybatis动态SQL构建通用自定义高级查询
下一篇
设计模式之创建型设计模式-简单工厂模式