工厂模式 vs 简单工厂:解耦与扩展性的比较
在软件设计中,工厂模式和简单工厂都是常用的设计模式,特别是在对象创建过程较为复杂时,它们能够帮助我们简化代码并增强系统的灵活性。虽然它们有相似之处,但工厂模式通过对工厂的进一步抽象,提供了更强的扩展性和更低的耦合度。本文将通过对比这两种模式,分析它们的区别以及工厂模式带来的具体好处。
什么是简单工厂?
简单工厂模式通过一个工厂类来负责对象的创建,根据传入的参数来决定实例化哪一个具体类。它通常只需要一个工厂类,所有的创建逻辑都集中在其中。以下是一个简单工厂模式的实现:
public class SimpleFactory {
public static Payment getPayment(String type) {
if ("WeChat".equals(type)) {
return new WeChatPayment();
} else if ("AliPay".equals(type)) {
return new AliPayPayment();
} else if ("UnionPay".equals(type)) {
return new UnionPayPayment();
}
return null;
}
}
简单工厂的问题:
- 不符合开闭原则:每次增加新的支付方式时,我们都需要修改
SimpleFactory
类,增加更多的else if
分支,随着产品的增多,代码会变得难以维护。 - 单一职责原则的违反:简单工厂集中了所有产品的创建逻辑,导致工厂类的职责过多,不利于代码的维护和扩展。
什么是工厂模式?
工厂模式进一步将工厂抽象化,定义了一个用于创建对象的接口,并将具体产品的创建逻辑延迟到子类中。这样,当我们需要扩展新的产品时,只需要创建新的工厂子类,而不需要修改原有的工厂类。这种设计遵循了开闭原则。
工厂模式的实现
-
抽象工厂接口:
首先,我们定义一个工厂接口,用于创建支付方式对象:public interface PaymentFactory { Payment createPayment(); }
-
具体工厂实现:
接下来,我们为每个具体的支付方式创建对应的工厂类:public class WeChatPaymentFactory implements PaymentFactory { public Payment createPayment() { return new WeChatPayment(); } } public class AliPayPaymentFactory implements PaymentFactory { public Payment createPayment() { return new AliPayPayment(); } } public class UnionPayPaymentFactory implements PaymentFactory { public Payment createPayment() { return new UnionPayPayment(); } }
-
使用工厂模式:
最后,业务逻辑中根据具体的工厂来获取支付方式:public class PaymentService { public Payment getPayment(PaymentFactory factory) { return factory.createPayment(); } }
工厂模式的优势
1. 符合开闭原则
工厂模式的最大优势在于它遵循了开闭原则,即对扩展开放、对修改封闭。当我们需要增加新的支付方式时,例如新增一个PayPal支付方式,只需要创建一个新的 PayPalPaymentFactory
,而无需修改现有的工厂类代码。这种设计避免了对已有代码的侵入性修改,减少了潜在的代码错误风险。
例如,当我们需要新增一个 PayPal 支付方式时,只需新增一个 PayPalPaymentFactory
类:
public class PayPalPaymentFactory implements PaymentFactory {
public Payment createPayment() {
return new PayPalPayment();
}
}
通过这种设计,我们的代码在面对需求变化时具有更好的扩展性。
2. 降低耦合度
简单工厂的所有创建逻辑都集中在一个类中,这导致工厂类承担了过多的责任。当系统需要添加新产品时,我们需要频繁修改工厂类,增加更多的判断逻辑。工厂模式通过将创建逻辑分散到各个具体工厂类中,解耦了产品的创建过程和具体工厂的实现,使得每个工厂类职责单一、清晰,便于维护和扩展。
3. 便于维护和测试
在工厂模式中,具体工厂类只负责创建某一种产品,职责单一。因此,在测试和维护时,可以更容易地定位和解决问题。每个工厂类的功能简单、清晰,减少了因为复杂判断逻辑导致的潜在问题。
示例对比
假设我们有一个支付系统,最初支持微信支付和支付宝支付,随着需求的变化,系统需要新增支持银联支付。使用简单工厂和工厂模式的实现对比如下:
1. 使用简单工厂
public class SimpleFactory {
public static Payment getPayment(String type) {
if ("WeChat".equals(type)) {
return new WeChatPayment();
} else if ("AliPay".equals(type)) {
return new AliPayPayment();
} else if ("UnionPay".equals(type)) {
return new UnionPayPayment();
}
return null;
}
}
每当我们需要新增支付方式时,比如 PayPal,我们需要修改工厂类,增加新的分支逻辑:
if ("PayPal".equals(type)) {
return new PayPalPayment();
}
问题:
- 工厂类会变得越来越复杂,难以维护。
- 每次增加新支付方式,都需要修改工厂类,违反了开闭原则。
2. 使用工厂模式
public interface PaymentFactory {
Payment createPayment();
}
public class WeChatPaymentFactory implements PaymentFactory {
public Payment createPayment() {
return new WeChatPayment();
}
}
public class AliPayPaymentFactory implements PaymentFactory {
public Payment createPayment() {
return new AliPayPayment();
}
}
public class UnionPayPaymentFactory implements PaymentFactory {
public Payment createPayment() {
return new UnionPayPayment();
}
}
当需要新增 PayPal 支付时,只需新增 PayPalPaymentFactory
类,而无需修改现有代码:
public class PayPalPaymentFactory implements PaymentFactory {
public Payment createPayment() {
return new PayPalPayment();
}
}
好处:
- 工厂类职责单一,代码清晰易维护。
- 新增支付方式时无需修改现有代码,符合开闭原则。
总结
简单工厂虽然简单易用,但其扩展性较差,当产品种类增加时,容易造成工厂类的复杂度增加。相比之下,工厂模式通过将工厂抽象化,允许我们通过新增具体工厂来扩展系统,而无需修改现有代码,极大地提升了系统的扩展性和维护性。因此,在需求多变、需要频繁扩展的系统中,工厂模式是一个更好的选择。
通过工厂模式,开发人员可以更好地遵循面向对象设计中的开闭原则,使系统更加灵活和易于维护。
改进点
虽然工厂模式相较于简单工厂已经将工厂进行抽象化更加符合开闭原则,但是细心的兄弟可能发现这本质不就是将if-else的判断放到了别的地方嘛,如你在获取具体工厂的时候你需要根据支付方式获取具体的工厂。这时候我们就可以加上一个注册器。