设计模式系列往期文章
前言
简单工厂不是一个标准的设计模式,但是非常简单又好用,在介绍工厂模式和抽象工厂模式前我们先介绍简单工厂。
1 定义
简单工厂模式(也叫静态工厂模式)是一种创建型设计模式,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类或接口。以下图为例举个例子:
- API定义客户所需要的功能接口
- Impl为API接口的具体实现类
- Factory是简单工厂,通过选择合适的实现类来创建API接口对象
- Client是客户端,通过Factory去获取API接口对象,然后面向API接口编程
使用接口,能够更好的封装隔离代码——只要接口不变,其内部实现的变化不会影响到Client的使用,从而使得系统更灵活,具有更好的扩展性和可维护性。
2 示例代码
2.1 示例1
以上面的类图为例,实现代码如下:
public interface Api {
public void operation(String s);
}
public class ImplA implements Api{
@Override
public void operation(String s) {
System.out.println("ImplA的实现代码" + s);
}
}
public class ImplB implements Api{
@Override
public void operation(String s) {
System.out.println("ImplB的实现代码" + s);
}
}
// 简单工厂类,通过Factory创建对象,将客户端和具体实现隔离开。
public class Factory {
public static Api createApi(int cond) {
Api api = null;
if (cond == 1) {
api = new ImplA();
} else {
api = new ImplB();
}
return api;
}
}
public class Client {
public static void main(String[] args) {
Api api = Factory.createApi(3);
api.operation("task");
}
}
2.2 示例2
以披萨店为例,一个披萨店可以制作各种口味的披萨,可以使用简单工厂模式定义一个静态方法orderPizza
,该方法接收一个披萨类型参数,然后返回对应的披萨实例:
// 披萨接口,定义披萨的行为
public interface Pizza {
void prepare(); // 准备
void bake(); // 烘焙
void cut(); // 切片
void box(); // 打包
}
// 奶酪披萨类,实现披萨接口
public class CheesePizza implements Pizza {
@Override
public void prepare() {
System.out.println("准备奶酪披萨的原料");
}
@Override
public void bake() {
System.out.println("烘焙奶酪披萨");
}
@Override
public void cut() {
System.out.println("切片奶酪披萨");
}
@Override
public void box() {
System.out.println("打包奶酪披萨");
}
}
// 海鲜披萨类,实现披萨接口
public class SeafoodPizza implements Pizza {
@Override
public void prepare() {
System.out.println("准备海鲜披萨的原料");
}
@Override
public void bake() {
System.out.println("烘焙海鲜披萨");
}
@Override
public void cut() {
System.out.println("切片海鲜披萨");
}
@Override
public void box() {
System.out.println("打包海鲜披萨");
}
}
// 披萨店类,提供一个静态方法根据参数创建不同种类的披萨对象
public class PizzaStore {
public static Pizza orderPizza(String type) {
Pizza pizza = null;
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("seafood")) {
pizza = new SeafoodPizza();
}
// 如果有其他种类的披萨,就需要修改这个方法的逻辑,增加判断分支
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
return pizza;
}
}
// 测试类,调用披萨店的静态方法创建和使用披萨对象
public class Test {
public static void main(String[] args) {
Pizza cheesePizza = PizzaStore.orderPizza("cheese"); // 创建奶酪披萨对象
Pizza seafoodPizza = PizzaStore.orderPizza("seafood"); // 创建海鲜披萨对象
// 如果想要其他种类的披萨,就需要传入不同的参数,但是如果没有对应的产品类和判断逻辑,就会返回null
}
}
3 总结
3.1 优点
- 使用接口,将具体的实现封装了起来,做到了解耦
- 通过引入工厂类,可在不修改任何客户端代码的情况下更换和增加新的具体产品类,提高了系统的灵活性。
3.2 缺点
- 工厂类集中了所有产品创建逻辑,职责过重,一旦发生异常,整个系统将受影响。
- 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
3.3 适用场景
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
不过,随着产品种类的增多,工厂生产也需要对应的增加,工厂内部的代码就需要不断的调整,那么就会违反SOLID原则中的开闭原则:一个软件实体应当对扩展开放,对修改关闭。那怎么解决呢?这个时候就需要使用到工厂方法模式,详见下文。