概述
工厂方法模式是一种常用的创建型设计模式,它通过将对象的创建过程封装在工厂类中,实现了创建与使用的分离。这种模式不仅提高了代码的复用性,还增强了系统的灵活性和可扩展性。本文将详细介绍工厂方法模式的三种形式:简单工厂模式、工厂方法模式和抽象工厂模式,并通过Java代码示例帮助你深入理解。
什么是工厂方法模式
工厂方法模式(Factory Method Pattern)由父类提供一个创建对象的方法,允许子类决定实例化对象的类型。这种模式的核心思想是解耦 - 将对象的创建过程与使用过程分离,使得代码更容易维护和扩展。
核心优势
- 解耦创建与使用:客户端不需要知道具体产品的创建细节
- 提高代码复用性:创建逻辑集中在工厂中,避免代码重复
- 增强系统扩展性:新增产品类型时只需添加相应的工厂类
简单工厂模式
简单工厂模式是最基础的工厂模式形式,它通过一个工厂类集中处理所有产品的创建逻辑。
实现原理
简单工厂通过一个静态方法根据传入的参数决定创建哪种产品对象。以下是基于动物示例的实现:
// 动物接口
public interface Animal {
void eat();
}
// 具体实现类 - 猫
public class Cat implements Animal {
@Override
public void eat() {
System.out.println("小猫吃鱼");
}
}
// 具体实现类 - 狗
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("小狗吃骨头");
}
}
// 具体实现类 - 猪
public class Pig implements Animal {
@Override
public void eat() {
System.out.println("小猪吃饲料");
}
}
// 简单工厂类 - 由YA33提供
public class SimpleAnimalFactory {
/**
* 根据动物名称创建对应的动物对象
* @param animalName 动物名称(cat/dog/pig)
* @return 对应的动物对象,如果名称不匹配则返回null
*/
public static Animal createAnimal(String animalName) {
if ("cat".equalsIgnoreCase(animalName)) {
return new Cat();
} else if ("dog".equalsIgnoreCase(animalName)) {
return new Dog();
} else if ("pig".equalsIgnoreCase(animalName)) {
return new Pig();
}
return null;
}
}
使用示例
// 测试类
public class SimpleFactoryTest {
public static void main(String[] args) {
// 通过工厂创建动物对象
Animal cat = SimpleAnimalFactory.createAnimal("cat");
if (cat != null) {
cat.eat(); // 输出: 小猫吃鱼
} else {
System.out.println("无法创建指定的动物");
}
// 尝试创建不存在的动物
Animal unknown = SimpleAnimalFactory.createAnimal("bird");
if (unknown == null) {
System.out.println("未知动物类型"); // 输出: 未知动物类型
}
}
}
优缺点分析
优点:
- 逻辑简单,易于理解
- 将创建逻辑封装,实现创建与使用的解耦
缺点:
- 不符合开闭原则(对扩展开放,对修改关闭)
- 新增产品类型时需要修改工厂类代码
- 工厂类职责过重,随着产品增多会变得臃肿
工厂方法模式
为了解决简单工厂模式的问题,工厂方法模式将产品的创建延迟到子类中,让子类决定实例化哪种产品。
实现原理
工厂方法模式定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。
// 抽象工厂接口
public interface AnimalFactory {
Animal createAnimal();
}
// 具体工厂 - 猫工厂
public class CatFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
System.out.println("创建一只小猫");
return new Cat();
}
}
// 具体工厂 - 狗工厂
public class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
System.out.println("创建一只小狗");
return new Dog();
}
}
// 具体工厂 - 猪工厂
public class PigFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
System.out.println("创建一只小猪");
return new Pig();
}
}
使用示例
// 测试类
public class FactoryMethodTest {
public static void main(String[] args) {
// 使用狗工厂创建狗
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.eat(); // 输出: 小狗吃骨头
// 使用猫工厂创建猫
AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.eat(); // 输出: 小猫吃鱼
}
}
优缺点分析
优点:
- 符合开闭原则,扩展性好
- 符合单一职责原则,每个工厂只负责一种产品
- 客户端不需要知道具体产品类名,只需要知道对应的工厂
缺点:
- 类的数量容易过多,增加系统复杂度
- 增加了系统的抽象性和理解难度
- 只能生产一种类型的产品(同一等级结构)
抽象工厂模式
抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
实现原理
抽象工厂模式包含多个工厂方法,每个工厂方法用于创建一个不同种类的对象。这些对象通常属于同一个产品族。
// 狗的子类型接口
public interface Dog extends Animal {
void bark();
}
// 具体狗类型 - 中华田园犬
public class RuralDog implements Dog {
@Override
public void eat() {
System.out.println("中华田园犬吃剩饭");
}
@Override
public void bark() {
System.out.println("中华田园犬: 汪汪!");
}
}
// 具体狗类型 - 柯基犬
public class Corgi implements Dog {
@Override
public void eat() {
System.out.println("柯基犬吃狗粮");
}
@Override
public void bark() {
System.out.println("柯基犬: 嗷呜!");
}
}
// 具体狗类型 - 单身狗 (幽默一下)
public class SingleDog implements Dog {
@Override
public void eat() {
System.out.println("单身狗吃狗粮(和自己做的饭)");
}
@Override
public void bark() {
System.out.println("单身狗: 呜呜...");
}
}
// 抽象工厂接口 - 由YA33设计
public interface DogFactory {
Dog createRuralDog();
Dog createCorgi();
Dog createSingleDog();
}
// 具体狗工厂
public class ConcreteDogFactory implements DogFactory {
@Override
public Dog createRuralDog() {
System.out.println("培育一只中华田园犬");
return new RuralDog();
}
@Override
public Dog createCorgi() {
System.out.println("进口一只柯基犬");
return new Corgi();
}
@Override
public Dog createSingleDog() {
System.out.println("发现一只单身狗");
return new SingleDog();
}
}
使用示例
// 测试类
public class AbstractFactoryTest {
public static void main(String[] args) {
DogFactory factory = new ConcreteDogFactory();
// 创建不同类型的狗
Dog ruralDog = factory.createRuralDog();
ruralDog.eat();
ruralDog.bark();
Dog corgi = factory.createCorgi();
corgi.eat();
corgi.bark();
Dog singleDog = factory.createSingleDog();
singleDog.eat();
singleDog.bark();
}
}
抽象工厂模式 vs 工厂方法模式
特性 | 工厂方法模式 | 抽象工厂模式 |
---|---|---|
产品等级 | 单一产品等级 | 多个产品等级 |
产品族 | 不支持产品族 | 支持产品族 |
扩展性 | 容易扩展新产品 | 难以扩展新产品族 |
复杂度 | 相对简单 | 相对复杂 |
适用场景 | 单一类型产品 | 相关产品家族 |
模式选择指南
在实际开发中,应根据具体需求选择合适的工厂模式:
- 简单工厂模式:适用于产品类型较少且不经常变化的场景
- 工厂方法模式:适用于产品类型可能扩展,但产品族单一的場景
- 抽象工厂模式:适用于需要创建多个相关产品族的场景
总结
工厂方法模式及其变体为我们提供了灵活的对象创建机制。通过将对象的创建过程封装起来,我们实现了创建与使用的分离,提高了代码的可维护性和扩展性。
- 简单工厂:简单易用,但违反开闭原则
- 工厂方法:遵循开闭原则,适合单一产品等级结构
- 抽象工厂:处理产品族,适合相关产品系列的创建
在实际项目中,我们应该根据具体需求选择合适的模式,避免过度设计。记住,最适合的才是最好的设计。