Preview
Skip to content
CodingDiary
返回

设计模式之创建型设计模式-简单工厂模式

编辑页面
导读

new LemonCandy() 散落在代码各处?简单工厂模式帮你统一管理对象创建!本文用「糖果工厂生产不同口味糖果」的场景,手把手实现简单工厂:抽象糖果类 → 具体糖果实现 → 工厂类封装创建逻辑。还有两种工厂方法实现:字符串参数和 Class 参数反射创建。附 Slf4j LoggerFactory 源码分析。

1. 模式简介

简单工厂模式(Simple Factory Pattern):它属于创建型设计模式不属于23种设计模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。本文将使用 糖果工厂生产不同口味的糖果 这个实际场景,用代码来实现 简单工厂模式

2. 模式角色

简单工厂包含3个角色:

  1. 工厂角色(CandyFactory):主要负责创建具体的实例。
  2. 抽象实体(Candy):它是工厂角色所创建的所有实例的父类,包含所有具体实例所共有的公共接口。
  3. 具体特征的实体(LemonCandyWatermelonCandy):所有由工厂角色创建出来的实例都属于具体实体。

3. UML图例

3.1. 未使用简单工厂模式的UML图

3.2. 使用简单工厂模式之后的UML图

4. 代码实现

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

Candy.java

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

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

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

LemonCandy.java

/**
 * <p>
 * 柠檬味糖果
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.simplefactory
 * @description: 柠檬味糖果
 * @author: yangkai.shen
 * @date: Created in 2019-02-13 10:34
 * @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.simplefactory
 * @description: 西瓜味糖果
 * @author: yangkai.shen
 * @date: Created in 2019-02-13 10:36
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class WatermelonCandy extends Candy {
    /**
     * 口味
     */
    @Override
    public void taste() {
        System.out.println("西瓜味");
    }
}

4.3. 步骤三:创建糖果工厂

CandyFactory.java

/**
 * <p>
 * 糖果工厂类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.simplefactory
 * @description: 糖果工厂类
 * @author: yangkai.shen
 * @date: Created in 2019-02-13 10:43
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class CandyFactory {
    /**
     * 生产糖果
     *
     * @param taste 具体口味
     * @return 对应口味的糖果
     */
    public Candy produceCandy(String taste) {
        if ("lemon".equalsIgnoreCase(taste)) {
            return new LemonCandy();
        } else if ("watermelon".equalsIgnoreCase(taste)) {
            return new WatermelonCandy();
        }
        return null;
    }

    /**
     * 生产糖果
     * @param c 具体口味的糖果类
     * @return 对应口味的糖果
     */
    public Candy produceCandy(Class c) {
        Candy candy = null;
        try {
            candy = (Candy) Class.forName(c.getSimpleName()).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return candy;
    }
}

4.4. 步骤四:调用工厂类生产具体口味的糖果

import com.xkcoding.design.pattern.creational.simplefactory.Candy;
import com.xkcoding.design.pattern.creational.simplefactory.CandyFactory;
import com.xkcoding.design.pattern.creational.simplefactory.LemonCandy;
import com.xkcoding.design.pattern.creational.simplefactory.WatermelonCandy;

/**
 * <p>
 * 简单工厂模式测试类
 * </p>
 *
 * @package: com.xkcoding.design.pattern.creational.simplefactory.run
 * @description: 简单工厂模式测试类
 * @author: yangkai.shen
 * @date: Created in 2019-02-13 10:40
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
public class PatternTest {
    public static void main(String[] args) {
        CandyFactory factory = new CandyFactory();
        // 测试工厂类方法 - 1
        Candy candy1 = factory.produceCandy("lemon");
        candy1.taste();
        Candy candy2 = factory.produceCandy("watermelon");
        candy2.taste();

        // 测试工厂类方法 - 2
        Candy candy3 = factory.produceCandy(LemonCandy.class);
        candy3.taste();
        Candy candy4 = factory.produceCandy(WatermelonCandy.class);
        candy4.taste();
    }
}

5. 应用

// Slf4j日志
// 获取日志对象 -> LoggerFactory.getLogger(String name) -> getILoggerFactory() -> getLogger(name)

6. 场景

7. 优缺点

优点: 以本例为例,1、糖果调用方想创建一个具体口味的糖果对象,只要知道其口味就可以。 2、扩展性高,如果想增加一个具体口味的糖果,只要在工厂类中添加一种生产逻辑就可以实现。 3、屏蔽糖果的具体实现,调用方只关心抽象实体的通用接口在具体口味糖果类中的不同实现。

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

8. 完整代码地址

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


编辑页面
分享到:

上一篇
设计模式之创建型设计模式-工厂方法模式
下一篇
使用Maven管理Spring Boot Profile