工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单使用的模式。简单工厂模式定义了一个创建对象的类,由这个类来封装实例化对象的行为。在软件开发中,当我们会用到大量的创建某种、某类或者某批量对象时,就会使用到工厂模式。

# 一、简单工厂模式案例

需求: 用户可以通过一个披萨工厂类来获取自己想要的披萨。 工厂模式设计方案:首先将披萨项目的实例抽象成抽象方法,在不同的口味子类中具体实现。同时定义一个披萨的工厂类 (SimplePizzaFactory)来获取想要的披萨对象。它向工厂类中传递信息(GREEK 等),以便获取它所需要的对象类型。 类图: 通过类图,查看构建的思路:如果有新的品种只需修改提供方,应用方无需修改。

工厂模式

【1】定义一个接口 Pizza

package com.yintong.principle.singleresponsibility;
//将Pizza 做成一个接口
public interface Pizza {
    //准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
    public void prepare();
}
1
2
3
4
5
6

【2】定义披萨的种类,实现 Pizza 接口,如下定义了 GREEK、CHEESE 两种披萨。如果后续有新的种类可以实现 Pizza 接口,继续添加新的品种。

//希腊披萨
public class GreekPizza implements Pizza{
 
    @Override
    public void prepare() {
        System.out.println(" 给希腊披萨 准备原材料 ");
    }
}
//奶酪披萨
public class CheesePizza implements Pizza{
 
    @Override
    public void prepare() {
        System.out.println(" 给制作奶酪披萨 准备原材料 ");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

【3】 创建一个简单的工厂类对象 SimpleFactory

public class SimpleFactory {
    //传入 orderType(种类) 返回对应的 Pizza 对象
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        //使用简单工厂模式
        if (orderType.equals("greek")) {
            //希腊披萨
            pizza = new GreekPizza();
        } else if (orderType.equals("cheese")) {
            //奶酪披萨
            pizza = new CheesePizza();
        }
        return pizza;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

【4】在应用代码 OrderPizza 中调用工厂类,获取用户需要的披萨对象。

public class OrderPizza {
    //定义用户要获取的披萨类型
    private static final String pizza = "greek";
    public static void main(String[] args) {
        //通过工厂获取希腊披萨
        SimpleFactory simpleFactory = new SimpleFactory();
        //greekPizza 就是我们需要获取的目标披萨
        Pizza greekPizza = simpleFactory.createPizza(pizza);
        //调用目标披萨的方法
        greekPizza.prepare();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 二、工厂模式的优缺点

优点:
1)、一个调用者想创建一个对象,只要知道其名称就可以了。
2)、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3)、屏蔽产品的具体实现,调用者只关心产品接口。

缺点: 每增加一个产品时,都需要增加一个具体实现类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

注意事项: 作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别只需要通过 new 就可以完成创建的对象,无需工厂模式。如果使用工厂模式就需要使用工厂类,会增加系统的复杂度。

# 三、抽象工厂方法模式

需求: 在上述的基础上,添加了地区。例如:用户可以点北京的奶酪披萨,北京的胡椒披萨,或者伦敦的奶酪披萨,伦敦的胡椒披萨。

工厂方法设计模式:
1)、定义一个 interface(工厂的接口) 用于创建相关或者依赖关系的对象簇,而无需指明具体对象类。
2)、从设计层面来看,抽象工厂模式就是简单工厂模式的改进(或者称为进一步抽象)。
3)、将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更有利于代码的维护和扩展。

类图: 将简单工厂模式中的工厂类抽象成了一个接口,易于后期扩展。

工厂模式

【1】定义工厂类的接口(AbsFactory)

//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {
    //让下面的工厂子类来 具体实现
    public Pizza createPizza(String orderType);
}
1
2
3
4
5

【2】让北京和伦敦的工厂类实现此接口(与简单工厂类的区别就是实现了 AbsFactory 接口,伦敦略)

public class BJFactory implements AbsFactory{
    //更加orderType 返回对应的Pizza 对象
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        //使用简单工厂模式
        if (orderType.equals("greek")) {
            //希腊披萨
            pizza = new GreekPizza();
        } else if (orderType.equals("cheese")) {
            //奶酪披萨
            pizza = new CheesePizza();
        }
        return pizza;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

【3】在 Order 订单应用中,与接口 AbsFactory 进行组合。

public class OrderPizza {
    AbsFactory factory;
    //定义构造器
    public OrderPizza(AbsFactory factory){
        this.factory = factory;
    }
    //定义用户要获取的披萨类型,可以定义一个变量从客户端传入
    private static final String pizza = "greek";
    public void main(String[] args) {
        //greekPizza 就是我们需要获取的目标披萨
        Pizza greekPizza = factory.createPizza(pizza);
        //调用目标披萨的方法
        greekPizza.prepare();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 四、工厂模式在 JDK-Calendar 类中的应用

//1、调用 Calendar 对象
Calendar instance = Calendar.getInstance();
//2、进入 Calendar.getInstance() 方法
public static Calendar getInstance()
{
    return createCalendar(TimeZone.getDefault(),Locale.getDefault(Locale.Category.FORMAT));
}
//3、进入 createCalendar 方法
private static Calendar createCalendar(TimeZone zone,Locale aLocale){
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                             .getCalendarProvider();
    if (provider != null) {
        try {
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
            // fall back to the default instantiation
        }
    }
 
    Calendar cal = null;
 
    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            //该出就是我们要重点查看的部分,根据用户需求,创建Calendar 对象
            switch (caltype) {
            case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
            }
        }
    }
    return cal;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 五、工厂模式小结

1)、工厂模式的意义: 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
2)、设计模式依赖抽象原则: 创建对象实例时,不要直接 new 类,而是把这个 new 类的动作放在一个工厂的方法中,并返回。不要让类继承具体类,而是继承抽象类或者实现 interface(接口)。不要覆盖基类中已经实现的方法。

(adsbygoogle = window.adsbygoogle || []).push({});