设计模式系列(二):工厂方法模式

俗话说,不会卖水果的程序员不是好的程序员。今天,我们就来卖水果。

简单工厂

因为水果店里的水果种类众多,我们这里选择使用简单工厂来实现。

需要说明的是,简单工厂其实并不能算是23个设计模式中的一个,它更像是一种编程习惯。

普通简单工厂

首先,我们需要创建出抽象产品类,这里当然就是水果咯。

1
2
3
public abstract class IFruit {
public abstract void description();
}

接着是具体产品类,显然这里是具体的各种水果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Apple extends Ifruit {
@Override
public void description() {
Log.d("Chen", "苹果,10块一斤");
}
}

public class Peach extends Ifruit {
@Override
public void description() {
Log.d("Chen", "桃子,12块一斤");
}
}

public class Pear extends Ifruit {
@Override
public void description() {
Log.d("Chen", "梨子,8块一斤");
}
}

然后就是我们的主角,简单工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FruitFactory {
public static final int TYPE_APPLE = 1; // 苹果
public static final int TYPE_PEACH = 2; // 桃子
public static final int TYPE_PEAR = 3; // 梨子

public IFruit creatFruit(int type) {
if (type == TYPE_APPLE) {
return new Apple();
} else if (type == TYPE_PEACH) {
return new Peach();
} else if (type == TYPE_PEAR) {
return new Pear();
} else {
throw new IllegalArgumentException("Wrong type.");
}
}
}

最后在我们的水果店就可以给顾客提供各种水果啦。正式开张,鼓掌!

这不,已经有顾客来买苹果了。

1
2
3
FruitFactory factory = new FruitFactory();
IFruit fruit = factory.creatFruit(FruitFactory.TYPE_APPLE);
fruit.description();

输出结果:

1
D/Chen: 苹果,10块一斤

静态简单工厂

一般在使用的时候,我们会将工厂类里的方法直接定义成静态的,这样就不用再new一个工厂对象出来了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FruitFactory {
public static final int TYPE_APPLE = 1; // 苹果
public static final int TYPE_PEACH = 2; // 桃子
public static final int TYPE_PEAR = 3; // 梨子

public static IFruit creatFruit(int type) {
if (type == TYPE_APPLE) {
return new Apple();
} else if (type == TYPE_PEACH) {
return new Peach();
} else if (type == TYPE_PEAR) {
return new Pear();
} else {
throw new IllegalArgumentException("Wrong type.");
}
}
}

调用时:

1
2
IFruit fruit = FruitFactory.creatFruit(FruitFactory.TYPE_APPLE);
fruit.description();

所以我们也把这种写法称为静态工厂

多方法简单工厂

细心的小伙伴可能已经发现了,上面的方法有一个缺点,如果creat()时传递的参数不正确,就会得不到想要的产品。

所以又出现了接下来多方法简单工厂这种写法。它为不同的产品,提供了不同的方法,这样容错率比较高。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class FruitFactory {
public static IFruit creatApple() {
return new Apple();
}

public static IFruit creatPeach() {
return new Peach();
}

public static IFruit creatPear() {
return new Pear();
}
}

依然还是以买苹果为例:

1
2
IFruit fruit = FruitFactory.creatApple();
fruit.description();

反射简单工厂

我们也可以通过反射,在工厂类里实现产品的创建。

1
2
3
4
5
6
7
8
9
10
11
public class FruitFactory {
public static <T extends IFruit> T createFruit(Class<T> clz) {
T result = null;
try {
result = (T) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}

调用时:

1
2
IFruit fruit = FruitFactory.createFruit(Apple.class);
fruit.description();

工厂模式

水果店生意越做越大,慢慢有了一个又一个的分店出现。这时候,就需要工厂模式出来帮忙了。

首先,将上面工厂类进行抽象,得到一个抽象工厂类

1
2
3
public abstract class FruitFactory {
public abstract IFruit creatFruit(int type);
}

接着是我们的分店,每个分店里卖的水果可能多种多样,各不相同。这里以第一分店为例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class FruitFactoryOne extends FruitFactory{
public static final int TYPE_APPLE = 1; // 苹果
public static final int TYPE_PEACH = 2; // 桃子
public static final int TYPE_PEAR = 3; // 梨子

@Override
public IFruit creatFruit(int type) {
if (type == TYPE_APPLE) {
return new Apple();
} else if (type == TYPE_PEACH) {
return new Peach();
} else if (type == TYPE_PEAR) {
return new Pear();
} else {
throw new IllegalArgumentException("Wrong type.");
}
}
}
1
2
3
FruitFactory factory = new FruitFactoryOne();
IFruit fruit = factory.creatFruit(FruitFactoryOne.TYPE_APPLE);
fruit.description();

接着的第二分店、第三分店等等,里面的水果种类可能不一样,会有桔子、香蕉,但写法结构都是一样的。

可以看出工厂模式的特点:不仅仅产品要抽象,工厂也需要抽象,它使得一个产品类的实例化延迟到具体的工厂子类。

这样可以更好的符合开闭原则。当需求变化时(比如再开一家分店),只需要增删想应的类,而不需要修改已有的方法。

总结

工厂模式的使用方法到此就介绍了差不多了,我们做一下最后的总结。

简单工厂和工厂方法的差别

简单工厂把所有事情,在一个地方都处理完了。然而工厂方法却是创立了一个框架,让子类决定要如何去做。

在刚刚的例子中可以看出,最突出的体现就是建立了抽象的工厂类。

这样,工厂方法会具有简单工厂所不具有的弹性,更能应对未来的扩展。

优点

  • 封装性良好,代码结构清晰。

  • 扩展性非常优秀。

  • 屏蔽产品类,是典型的解耦框架。

实践

工厂方法模式在项目中使用非常频繁,但这并不代表每个人都可以用得很好。平时一定要多思考工厂方法如何使用,才能够做到熟练掌握。

而且工厂方法模式还可以与其他模式(比如单例模式、模板方法、原型模式等)混合使用,变化出无穷的优秀设计。

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类

Chen wechat
欢迎扫描二维码,订阅我的博客公众号MiracleChen