Appearance
工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。本文会先从简单方法模式入手,带你掌握工厂方法模式,以及下一篇的抽象工厂模式。
简单工厂模式
适用场景
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数对于如何创建对象(逻辑)不关心
优缺点
- 优点:只需要传入一个正确的参数,就可以获取你所需要的对象而无须知道其创建细节
- 缺点:工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则
实现步骤
- 创建抽象产品类,里面有产品的抽象方法,由具体的产品类去实现
- 创建具体产品类,继承了他们的父类,并实现具体方法
- 创建工厂类,提供了一个静态方法createXXX用来生产产品,只需要传入你想产品名称
具体实现
抽象支付类
java
public interface Pay {
void unifiedorder();
}
具体实现类,支付宝支付
java
public class AliPay implements Pay{
@Override
public void unifiedorder() {
System.out.println("支付宝支付 统一下单接口");
}
}
具体实现类,微信支付
java
public class WechatPay implements Pay{
@Override
public void unifiedorder() {
System.out.println("微信支付 统一下单接口");
}
}
创建简单工厂类
java
public class SimplePayFactory {
/**
* 根据参数返回对应的支付对象
* @param payType 参数
* @return 具体的支付对象
*/
public static Pay createPay(String payType) {
if (payType == null) {
return null;
}
if (payType.equalsIgnoreCase("WECHAT_PAY")) {
return new WechatPay();
} else if (payType.equalsIgnoreCase("ALI_PAY")) {
return new AliPay();
}
return null;
}
}
使用:
java
public class Main {
public static void main(String[] args) {
Pay pay = SimplePayFactory.createPay("WECHAT_PAY");
pay.unifiedorder();
}
}
小结
- 优点:将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
- 缺点:
- 工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背
- 即开闭原则(Open ClosePrinciple)对扩展开放,对修改关闭,程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果
- 将会增加系统中类的个数,在一定程度上增加了系统的复杂度和理解难度,不利于系统的扩展和维护,创建简单对象就不用模式
抛砖引玉
假设你正在开发一款物流管理应用。 最初版本只能处理卡车运输, 因此大部分代码都在位于名为 卡车
的类中。一段时间后, 这款应用变得极受欢迎。 你每天都能收到十几次来自海运公司的请求, 希望应用能够支持海上物流功能。如果代码其余部分与现有类已经存在耦合关系, 那么向程序中添加新类其实并没有那么容易。
这可是个好消息。 但是代码问题该如何处理呢? 目前, 大部分代码都与 卡车
类相关。 在程序中添加 轮船
类需要修改全部代码。 更糟糕的是, 如果你以后需要在程序中支持另外一种运输方式, 很可能需要再次对这些代码进行大幅修改。
最后, 你将不得不编写繁复的代码, 根据不同的运输对象类, 在应用中进行不同的处理。
工厂方法模式
- 又称工厂模式,是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则
- 通过工厂父类定义负责创建产品的公共接口,通过子类来确定所需要创建的类型
- 相比简单工厂而言,此种方法具有更多的可扩展性和复用性,同时也增强了代码的可读性
- 将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化哪一个类。
工厂方法模式图解:
核心组成
IProduct:抽象产品类,描述所有实例所共有的公共接口
Product:具体产品类,实现抽象产品类的接口,工厂类创建对象,如果有多个需要定义多个
IFactory:抽象工厂类,描述具体工厂的公共接口
Factory:具体工场类,实现创建产品类对象,实现抽象工厂类的接口,如果有多个需要定义多个
具体实现
Pay接口、AliPay和WechatPay类不变,新建工厂
java
public interface PayFactory {
Pay getPay();
}
支付宝工厂
java
public class AliPayFactory implements PayFactory {
@Override
public Pay getPay() {
return new AliPay();
}
}
微信工厂
java
public class WechatPayFactory implements PayFactory {
@Override
public Pay getPay() {
return new WechatPay();
}
}
使用:
java
public class Main {
public static void main(String[] args) {
PayFactory payFactory = new AliPayFactory();
Pay pay = payFactory.getPay();
pay.unifiedorder();
}
}
优点:
符合开闭原则,增加一个产品类,只需要实现其他具体的产品类和具体的工厂类;
符合单一职责原则,每个工厂只负责生产对应的产品
使用者只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则
迪米特法则:最少知道原则,实体应当尽量少地与其他实体之间发生相互作用
依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体
里氏替换原则:俗称LSP, 任何基类可以出现的地方,子类一定可以出现,对实现抽象化的具体步骤的规范
缺点:
增加一个产品,需要实现对应的具体工厂类和具体产品类;每个产品需要有对应的具体工厂和具体产品类。