1. 概念
工厂(Factory)顾名思义就是创建对象实例的生产工厂。
以前创建对象都是 new Xxx(),如果使用工厂模式 的话就可以用它来替代 new 操作创建实例(对象)。所以理解了工厂模式后,以后去 new 对象时就可以考虑还能使用工厂模式达到一样的目的。虽然这样做可能需要多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量(主要是降低耦合)。
工厂模式分为三种:简单工厂模式、工厂方法模式、抽象工厂模式。
2. 简单工厂模式
2.1 概念
简单工厂模式不属于GOF的23种经典设计模式,严格来说它应该属于一种编程习惯,这个简单工厂模式只是工厂方法模式的一种特例,所以工厂模式实际上只有工厂方法模式和抽象工厂模式。
简单工厂比较适合创建对象较少的场景。
2.2 优缺点
优点:
- 解耦: 客户端代码与具体产品类解耦,客户端只依赖于产品接口,便于扩展和维护。
- 集中管理: 所有对象的创建逻辑集中在工厂类中,方便管理和修改。
- 简化对象创建: 客户端不需要知道具体的创建过程,只需调用工厂方法即可。
缺点:
- 不符合开闭原则: 当需要添加新产品时,必须修改工厂类的代码,违反了开闭原则(对扩展开放,对修改关闭)。
- 工厂类职责过重: 工厂类需要处理所有产品的创建逻辑,可能导致类变得庞大且复杂。
- 难以扩展: 如果产品种类增多,工厂类会变得越来越复杂,维护难度增加。
2.3 组成结构
- 产品接口(Product): 定义产品的公共接口,所有具体产品都需要实现这个接口。
- 具体产品(Concrete Product): 实现产品接口的具体类,代表工厂所创建的具体对象。
- 工厂类(Factory): 提供一个静态方法,根据不同的参数返回不同的具体产品对象。
2.4 举例
产品接口
public interface Animal {
void sound();
}
具体产品
public class Cat implements Animal {
@Override
public void sound() {
System.out.println("喵喵");
}
}
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("汪汪");
}
}
工厂类
public class AnimalFactory {
public static Animal createAnimal(String type) {
if (type.equalsIgnoreCase("cat")) {
return new Cat();
} else if (type.equalsIgnoreCase("dog")) {
return new Dog();
}
return null;
}
}
客户端使用测试
public class Test {
public static void main(String[] args) {
Animal cat = AnimalFactory.createAnimal("cat");
cat.sound(); // 输出:喵喵
Animal dog = AnimalFactory.createAnimal("dog");
dog.sound(); // 输出:汪汪
}
}
2.5 总结
简单工厂模式适用于产品种类较少且变化不大的场景,但在产品种类较多且经常变化的情况下,使用工厂方法模式或抽象工厂模式可能更为合适。
3. 工厂方法模式
3.1 概念
核心思想:将对象的创建逻辑下沉到子类里面(创建多个子工厂来创建对象)
这种方式如果再要增加新的类型时,就不需要修改工厂类的代码了,每个实例类都会有一个工厂,这样就解决了简单工厂模式的缺点,不过要相应地增加工厂类。工厂方法模式是简单工厂模式的进一步抽象,运用了多态性、克服了简单工厂模式的缺点。
3.2 优缺点
优点:获取对象时只需要知道具体工厂的名称,就可以得到对应的对象,无须知道具体创建过程;在系统增加新的类时只需要添加对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。
缺点:每增加一个类就要增加一个对应的具体工厂类,增加了系统的复杂度。
3.3 组成部分
- 产品接口:定义了产品的接口。
- 具体产品:实现了产品接口的具体类。
- 工厂接口:定义了创建产品的工厂方法。
- 具体工厂:实现了工厂接口,返回具体产品的实例。
3.4 举例
产品接口
public interface Shape {
void draw();
}
具体产品
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Circle");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Rectangle");
}
}
工厂接口
public interface ShapeFactory {
Shape createShape();
}
具体工厂
public class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Circle();
}
}
public class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle();
}
}
客户端使用
public class Test {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.createShape();
circle.draw(); // 输出: Drawing a Circle
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw(); // 输出: Drawing a Rectangle
}
}
3.5 总结
在这个例子中,我们定义了一个 Shape 接口和两个实现类 Circle 和 Rectangle。通过工厂接口 ShapeFactory 和其具体实现类 CircleFactory 和 RectangleFactory,我们可以根据需要创建不同的形状实例,遵循了工厂方法模式的设计理念。这样,增加新的形状只需添加新的产品类和工厂类,而无需修改现有代码,符合开闭原则。
4. 抽象工厂模式
4.1 概念
抽象工厂模式是一种创建型设计模式,提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。它通过定义一个工厂接口及其实现类来生成对象,使得客户端代码与具体类解耦。
4.2 优缺点
优点
- 解耦:客户端不需要知道具体类的实现,降低了系统的耦合度。
- 可扩展性:增加新产品系列时,只需添加新的工厂类而不影响现有代码。
一致性:可以确保产品的创建符合一定的标准和一致性。
缺点
- 类的数量增加:每增加一个产品系列,就需要增加一个具体工厂,可能导致类的数量激增。
- 难以支持新种类的产品:如果需要添加新的产品类型,可能需要修改现有的工厂接口。
4.3 组成结构
- 抽象工厂(AbstractFactory):定义创建产品的接口。
- 具体工厂(ConcreteFactory):实现抽象工厂接口,创建具体产品。
- 抽象产品(AbstractProduct):定义产品的接口。
- 具体产品(ConcreteProduct):实现抽象产品接口的具体类。
4.4 举例
抽象产品
public interface Payment {
void pay();
}
public interface Refund {
void refund();
}
具体产品
public class Alipay implements Payment {
@Override
public void pay() {
System.out.println("使用支付宝支付");
}
}
public class AlipayRefund implements Refund {
@Override
public void refund() {
System.out.println("使用支付宝退款");
}
}
public class WeChatPay implements Payment {
@Override
public void pay() {
System.out.println("使用微信支付");
}
}
public class WeChatRefund implements Refund {
@Override
public void refund() {
System.out.println("使用微信退款");
}
}
抽象工厂
public interface PaymentFactory {
Payment createPayment();
Refund createRefund();
}
具体工厂
public class AlipayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new Alipay();
}
@Override
public Refund createRefund() {
return new AlipayRefund();
}
}
public class WeChatPayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new WeChatPay();
}
@Override
public Refund createRefund() {
return new WeChatRefund();
}
}
客户端使用
public class Test {
public static void main(String[] args) {
PaymentFactory alipayFactory = new AlipayFactory();
Payment alipay = alipayFactory.createPayment();
Refund alipayRefund = alipayFactory.createRefund();
alipay.pay();
alipayRefund.refund();
PaymentFactory weChatFactory = new WeChatPayFactory();
Payment weChatPay = weChatFactory.createPayment();
Refund weChatRefund = weChatFactory.createRefund();
weChatPay.pay();
weChatRefund.refund();
}
}
类图
4.5 总结
使用场景:
- 当系统需要独立于其产品的创建、组合和表示时。
- 当系统需要使用多个产品族中的对象时。
- 当产品的组合需要保持一致性时。
5 总结
简单工厂:产品的工厂。适用于简单的对象创建,适合小型项目。
工厂方法:工厂的工厂。适用于需要灵活扩展的项目,适合中型项目。
抽象工厂:复杂产品的工厂。适用于需要多个产品族的复杂系统,适合大型项目。