创建型模式之工厂模式

in HandbookDesign Patterns with 20 comments, viewed 35094 times

1 概述

创建型模式,提供了一种创建对象的最佳实践。工厂方法模式(Factory Method Pattern)的核心思想,是通过统一的工厂类来获取对象,而不需要调用类的构造方法。

2 优点

  1. 可以将类的实例化过程延缓到子类。调用者无需知道接口/抽象类的具体实现是什么,利用工厂方法即可获取类的实例,降低与调用者的耦合度。
  2. 隐藏类的构造细节,降低类创建的复杂度,提高程序可读性。
  3. 可以根据不同环境/参数,从工厂构造不同的方法。

3 案例

有一个饭店的接口,饭店里有厨师和服务员。我们定义KFCPizzaHut两个饭店:

interface Restaurant {
    void getCook();
    void getWaiter();
}

public class KFC implements Restaurant {

    @Override
    public void getCook() {
        System.out.println("I'm KFC cook.");
    }

    @Override
    public void getWaiter() {
        System.out.println("I'm KFC waiter.");
    }
}

class PizzaHut implements Restaurant {

    @Override
    public void getCook() {
        System.out.println("I'm PizzaHut cook.");
    }

    @Override
    public void getWaiter() {
        System.out.println("I'm PizzaHut waiter.");
    }
}

3.1 工厂类型1

再定义一个工厂方法RestaurantFactory,从工厂中,很容易就能根据类型获取对应的饭店:

public class Test {
    public static void main(String[] args) {
        RestaurantFactory factory = new RestaurantFactory();
        Restaurant kfc = factory.createRestaurant(RestaurantFactory.RestaurantType.KFC);
        Restaurant pizzaHut = factory.createRestaurant(RestaurantFactory.RestaurantType.PizzaHut);
        kfc.getCook();
        pizzaHut.getWaiter();
    }
}

class RestaurantFactory {
    enum RestaurantType {
        KFC, PizzaHut
    }

    Restaurant createRestaurant(RestaurantType type) {
        switch (type) {
            case KFC: return new KFC();
            case PizzaHut: return new PizzaHut();
            default: System.out.format("Invalid restaurant %s", type); return null;
        }
    }
}

输出:

I'm KFC cook.
I'm PizzaHut waiter.

UML:
UML for factory type1

比如Spring中的BeanFactory使用的就是这种模式:getBean方法用Bean类型/名字作为参数,返回对应的Bean
JDK中的Calendar类,也是用的这种模式:

public static Calendar getInstance(TimeZone zone, Locale aLocale) {
    ...
    // 根据参数创建不同的Calendar实例
    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            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;
            }
        }
    }
    ...
}

如果实例类型相对固定,那么上述模式能很好的满足需求。但是如果实例类型不确定,那么每当需要新增类型的时候,都需要改动原先的方法,对开闭原则遵循得不好。于是有了第二种类型。

3.2 工厂类型2

依然是饭店的例子,我们通过如下方式定义工厂:

public class Test {
    public static void main(String[] args) {
        KFCFactory kfcFactory = new KFCFactory();
        PizzaHutFactory pizzaHutFactory = new PizzaHutFactory();
        Restaurant kfc = kfcFactory.createRestaurant();
        Restaurant pizzaHut = pizzaHutFactory.createRestaurant();
        kfc.getCook();
        pizzaHut.getWaiter();
    }
}

class KFCFactory {
    Restaurant createRestaurant() {
        return new KFC();
    }
}

class PizzaHutFactory {
    Restaurant createRestaurant() {
        return new PizzaHut();
    }
}

输出:

I'm KFC cook.
I'm PizzaHut waiter.

UML:
UML for factory type2

上述方式,每新增一个类别,只需要新增一个对应的工厂即可,原先的工厂方法以及实例无需做任何修改。如LoggerFactory)就是这种类型的工厂模式:

public static Logger getLogger(String name) {
    // getLogger最终是委托给ILoggerFactory去做的。
    // 新增Logger获取方式,只需新增ILoggerFactory的实现类,扩展性很强。
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
}

但是这种方式,对每一种类别,都要有一个工厂类,复杂度相对较高。实际中,还是第一种类型使用比较频繁。

4 总结

工厂方法模式是使用很广泛的一种创建型模式,几乎能在所有的开源框架中见到。很典型的特点就是,工厂类以Factory字样结尾:-)。

文中例子的github地址

Responses / Cancel Reply
  1. 娛樂城
    娛樂城

    Reply
  2. 娛樂城

    Reply
  3. 太達數位媒體

    https://deltamarketing.com.tw/

    Reply
  4. 娛樂城

    Reply
  5. 娛樂城

    Reply
  6. 娛樂城

    Reply
  7. 娛樂城

    Reply
  8. 娛樂城
    娛樂城

    Reply
  9. 九州娛樂城

    Reply
  10. 魔龍傳奇

    Reply
  11. 魔龍傳奇
    魔龍傳奇

    Reply
  12. 魔龍傳奇

    Reply
  13. 魔龍傳奇
    魔龍傳奇

    Reply
  14. unethost無限空間虛擬主機 技術分享部落格

    http://blog.unethost.com/

    Reply
  15. 水微晶玻尿酸 - 八千代

    https://yachiyo.com.tw/hyadermissmile-injection/

    Reply
  16. 房屋貸款

    Reply
  17. 機車貸款

    Reply
  18. 貸款 db4293b

    Reply
  19. 百家樂
    百家樂

    Reply
  20. 百家樂
    百家樂

    Reply