02 工厂模式

2021年5月21日-2021年5月26日

1 工厂模式简介

它提供了一种创建对象的最佳方式,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

例子:

  • 需要购买一辆车,不用管车辆如何组装,且可以购买不同类型的。比如:轿车、SUV、跑车,直接去4s店购买就行(4s店就是工厂)。
  • 工厂生产电脑,除了A品牌、还可以生产B、C、D品牌。
  • 业务开发中,订单很常见,里面有统一支付、退款接口等,具体的支付实现可以是微信、支付宝、银行卡等。

工厂模式有 3 种不同的实现方式:

  • 简单工厂模式:通过传入相关的类型来返回相应的类,这种方式比较单一,可扩展性相对较差。
  • 工厂方法模式:通过实现类实现相应的方法来决定相应的返回结果,这种方式的可扩展性比较强。
  • 抽象工厂模式:基于上述两种模式的拓展,且支持细化产品。

应用场景:

  • 解耦:分离职责,把复杂对象的创建和使用的过程分开。
  • 复用代码,降低维护成本:
    • 如果对象创建复杂且多处需用到,如果每处都进行编写,则很多重复代码,如果业务逻辑发生了改变,需要四处修改;
    • 使用工厂模式统一创建,则只要修改工厂类即可,降低成本。

2 简单工厂模式

简单工厂模式又称静态工厂方法模式,可以根据参数的不同返回不同类的实例,专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

由于工厂方法是静态方法,可通过类名直接调用,而且只需要传入简单的参数即可。

核心组成

  • Factory:工厂类,简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。
  • IProduct:抽象产品类,简单工厂模式所创建的所有对象的父类,描述所有实例所共有的公共接口。
  • Product:具体产品类,是简单工厂模式的创建目标。

实现步骤

  • 创建抽象产品类,里面有产品的抽象方法,由具体的产品类去实现。--IProduct
  • 创建具体产品类,继承了他们的父类,并实现具体方法。--Product
  • 创建工厂类,提供了一个静态方法createXXX()用来生产产品,只需要传入你想要的产品名称。--Factory

优点

  • 将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。

缺点

  • 工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背。
  • 开闭原则(Open Close Principle)对扩展开放,对修改关闭,程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。
  • 将会增加系统中类的个数,在一定程度上增加了系统的复杂度和理解难度,不利于系统的扩展和维护,创建简单对象就不用工厂模式。

电商支付应用案例

注:示例代码中将上图的Order换成了订单中具体一种操作Pay。

  • IProduct-抽象产品类
public interface Pay {
    /**
     * 统一下单
     */
    void unifiedorder();
}
  • Product-具体产品类
public class AliPay implements Pay {
    @Override
    public void unifiedorder() {
        System.out.println("支付宝支付 统一下单接口");
    }
}
public class WechatPay implements Pay {
    @Override
    public void unifiedorder() {
        System.out.println("微信支付支付 统一下单接口");
    }
}
  • Factory-工厂类
public class SimplePayFactory {
    /**
     * 根据参数 返回对应的支付对象
     *
     * @param payType
     * @return
     */
    public static Pay createPay(String payType) {

        if (payType == null) {
            return null;
        } else if (payType.equalsIgnoreCase("WECHAT_PAY")) {
            return new WechatPay();
        } else if (payType.equalsIgnoreCase("ALI_PAY")) {
            return new AliPay();
        }

        // 想拓展,直接编写更多
        return null;
    }
}
  • 使用
Pay pay = SimplePayFactory.createPay("WECHAT_PAY");
pay.unifiedorder();
// 或
Pay pay = SimplePayFactory.createPay("ALI_PAY");
pay.unifiedorder();

3 工厂方法模式

工厂方法模式又称工厂模式,是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

通过工厂父类定义负责创建产品的公共接口,通过子类来确定所需要创建的类型。相比简单工厂而言,此种方法具有更多的可扩展性和复用性,同时也增强了代码的可读性。将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化哪一个类。

核心组成

  • IProduct:抽象产品类,描述所有实例所共有的公共接口。
  • Product:具体产品类,实现抽象产品类的接口,工厂类创建对象,如果有多个需要定义多个。
  • IFactory:抽象工厂类,描述具体工厂的公共接口。
  • Factory:具体工厂类,实现创建产品类对象,实现抽象工厂类的接口,如果有多个需要定义多个。

优点

  • 符合开闭原则,增加一个产品类,只需要实现其他具体的产品类和具体的工厂类。
  • 符合单一职责原则,每个工厂只负责生产对应的产品。
  • 使用者只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
    • 迪米特法则:最少知道原则,实体应当尽量少地与其他实体之间发生相互作用。
    • 依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体。
    • 里氏替换原则:俗称LSP,任何基类可以出现的地方,子类一定可以出现,对实现抽象化的具体步骤的规范。

缺点

  • 增加一个产品,需要实现对应的具体工厂类和具体产品类。
  • 每个产品需要有对应的具体工厂和具体产品类。

电商支付应用案例

注:示例代码中将上图的Order换成了订单中具体一种操作Pay。

  • IProduct-抽象产品类
public interface Pay {
    /**
     * 统一下单
     */
    void unifiedorder();
}
  • Product-具体产品类
public class AliPay implements Pay {
    @Override
    public void unifiedorder() {
        System.out.println("支付宝支付 统一下单接口");
    }
}
public class WechatPay implements Pay {
    @Override
    public void unifiedorder() {
        System.out.println("微信支付支付 统一下单接口");
    }
}
  • IFactory-抽象工厂类
/**
 * 抽象工厂方法
 */
public interface PayFactory {
    Pay createPay();
}
  • Factory-具体工厂类
/**
 * 具体产品工厂
 */
public class AliPayFactory implements PayFactory {
    @Override
    public Pay createPay() {
        return new AliPay();
    }
}

public class WechatPayFactory implements PayFactory {
    @Override
    public Pay createPay() {
        return new WechatPay();
    }
}
  • 使用
PayFactory aliPayFactory = new AliPayFactory();
PayFactory aliPay = aliPayFactory.getPay();
aliPay.unifiedorder();
// 或
PayFactory wechatPayFactory = new WechatPayFactory();
PayFactory wechatPay = wechatPayFactory.getPay();
wechatPay.unifiedorder();

4 抽象工厂模式

抽象工厂模式,是基于上述两种模式的拓展,是工厂方法模式的升级版,当需要创建的产品有多个产品线时使用抽象工厂模式是比较好的选择。

抽象工厂模式是在spring中应用最为广泛的一种设计模式。

背景:

工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责过重的问题。但工厂方法模式中每个工厂只创建一类具体类的对象,后续发展可能会导致工厂类过多,因此将一些相关的具体类组成一个“具体类族”,由同一个工厂来统一生产。抽象工厂模式强调的是一系列相关的产品对象。

(1) 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

(2) 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。

抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。

在这里,我觉得抽象工厂这个模式取的不太贴切。因为工厂方法模式较之简单工厂模式,就引入了抽象工厂的概念;而所谓的抽象工厂模式较之工厂方法模式,引入的是产品族概念。所以我觉得把抽象工厂模式理解为产品族工厂模式,或者多产品工厂模式较为形象。--dawson

核心组成

  • IProduct:抽象产品类,描述所有实例所共有的公共接口。(抽象工厂模式中有多个抽象产品类,即产品族;而工厂方法模式中只有一个。)
  • Product:具体产品类,实现抽象产品类的接口,工厂类创建对象,如果有多个需要定义多个。(有多少种抽象产品,就有多少种具体产品。)
  • IFactory:抽象工厂类,描述具体工厂的公共接口。
  • Factory:具体工厂类,实现创建产品类对象,实现抽象工厂类的接口,如果有多个需要定义多个。(抽象工厂模式中每个具体工厂可以生产多种不同的产品,即产品族;而工厂方法模式中每个具体工厂只可生产一种产品。)

实现步骤

  1. 定义两个接口PayRefund
  2. 创建具体的Pay产品、创建具体的Refund产品。
  3. 创建抽象工厂OrderFactory接口,里面有两个方法createPay()/createRefund()
  4. 创建支付宝产品族AliOderFactory,实现OrderFactory抽象工厂。
  5. 创建微信支付产品族WechatOderFactory,实现OrderFactory抽象工厂。
  6. 定义一个超级工厂创造器,通过传递参数获取对应的工厂。

优点

  • 当一个产品族中的多个对象被设计成一起工作时,它能保证使用方始终只使用同一个产品族中的对象。
  • 产品等级结构扩展容易,如果需要增加多一个产品等级,只需要增加新的工厂类和产品类即可,比如增加银行支付、退款。

缺点

  • 产品族扩展困难,要增加一个系列的某一产品,需要在抽象的工厂和具体的工厂里修改代码,不是符合开闭原则。
  • 增加了系统的抽象性和理解难度。

电商支付应用案例

  • IProduct-抽象产品-Pay
/**
 * 支付抽象接口
 */
public interface Pay {
    /**
     * 统一支付
     */
    void unifiedorder();
}
  • Product-具体产品-Pay
public class WechatPay implements Pay {
    @Override
    public void unifiedorder() {
        System.out.println("微信支付支付 统一下单接口");
    }
}
public class AliPay implements Pay {
    @Override
    public void unifiedorder() {
        System.out.println("支付宝支付 统一下单接口");
    }
}
  • IProduct-抽象产品-Refund
/**
 * 退款抽象接口
 */
public interface Refund {
    /**
     * 退款
     */
    void refund();
}

=-=

  • Product-具体产品-Refund
public class WechatRefund implements Refund {
    @Override
    public void refund() {
        System.out.println("微信支付 退款");
    }
}
public class AliRefund implements Refund {
    @Override
    public void refund() {
        System.out.println("支付宝 退款");
    }
}

=-=

  • IFactory-抽象工厂(工厂的工厂)
public interface OrderFactory {
    Pay createPay();
    Refund createRefund();
}
  • Factory-具体工厂-WeChatOrderFactory
public class WechatOrderFactory implements OrderFactory {
    @Override
    public Pay createPay() {
        return new WechatPay();
    }

    @Override
    public Refund createRefund() {
        return new WechatRefund();
    }
}
  • Factory-具体工厂-AliOrderFactory
public class AliOrderFactory implements OrderFactory {
    @Override
    public Pay createPay() {
        return new AliPay();
    }

    @Override
    public Refund createRefund() {
        return new AliRefund();
    }
}
  • 使用
OrderFactory orderFactory = new WechatOrderFactory();
orderFactory.createPay().unifiedorder();
orderFactory.createRefund().refund();
// 或
OrderFactory orderFactory = new AliOrderFactory();
orderFactory.createPay().unifiedorder();
orderFactory.createRefund().refund();
  • 这里做一个改进,让客户端不new对象,直接像简单工厂模式一样传字符串就行了。
  • (把简单工厂模式的优点拿过来,当然工厂方法模式也可以这样用,所以这不是抽象工厂模式和工厂方法模式区分点。真正的区分点是抽象工厂模式引入了产品族。)
  • 超级工厂创造器
public class FactoryProducer {
    public static OrderFactory getFactory(String type) {
        if (type.equalsIgnoreCase("WECHAT")) {
            return new WechatOrderFactory();
        } else if (type.equalsIgnoreCase("ALI")) {
            return new AliOrderFactory();
        }
        return null;
    }
}
  • 使用
OrderFactory orderFactory = FactoryProducer.getFactory("ALI");
orderFactory.createPay().unifiedorder();
orderFactory.createRefund().refund();
posted @ 2021-05-27 23:13  ddhhdd  阅读(113)  评论(0)    收藏  举报