创建型模式之工厂模式

编程

1 概述

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

2 优点

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

3 案例

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

interface Restaurant {

void getCook();

void getWaiter();

}

public class KFC implements Restaurant {

[@Override](https://my.oschina.net/u/1162528)

public void getCook() {

System.out.println("I"m KFC cook.");

}

[@Override](https://my.oschina.net/u/1162528)

public void getWaiter() {

System.out.println("I"m KFC waiter.");

}

}

class PizzaHut implements Restaurant {

[@Override](https://my.oschina.net/u/1162528)

public void getCook() {

System.out.println("I"m PizzaHut cook.");

}

[@Override](https://my.oschina.net/u/1162528)

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.

比如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.

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

public static Logger getLogger(String name) {

// getLogger最终是委托给ILoggerFactory去做的。

// 新增Logger获取方式,只需新增ILoggerFactory的实现类,扩展性很强。

ILoggerFactory iLoggerFactory = getILoggerFactory();

return iLoggerFactory.getLogger(name);

}

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

4 总结

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

文中例子的github地址

以上是 创建型模式之工厂模式 的全部内容, 来源链接: utcz.com/z/514592.html

回到顶部