DesignPattern - 工厂模式【建立型】

欢迎关注微信公众号:FSA全栈行动 👋java

1、工厂模式介绍

工厂模式提供了一种建立对象的最佳方式,咱们在建立对象时不会对客户端暴露建立逻辑,而且是经过使用一个共同的接口来指向新建立的对象。微信

  • 例子:
    • 须要购买一辆车,不用管车辆如何组装,且能够购买不一样类型的汽车,好比轿车、SUV、跑车,直接去 4s 店购买就行(4s 店就是工厂)
    • 工厂生产电脑,除了 A 品牌、还能够生产 B、C、D 品牌电脑
    • 支付业务开发,会统一下单和支付接口,具体的支付实现能够是微信、支付、银行卡等
  • 分类:
    • 简单工厂模式:经过传入相关的类型来返回相应的类,这种方式比较单一,可扩展性较差。
    • 工厂方法模式:经过实现类 实现相应的方法来决定相应的返回结果,这种方式的可扩展性比较强。
    • 抽象工厂模式:基于上述两种模式的扩展,且支持细化产品。
  • 应用场景:
    • 解耦:分离职责,把复杂对象的建立和使用的过程分开
    • 复用代码,下降维护成本:
      • 若是对象建立复杂且多处须要用到,若是每处都进行编写,则不少重复代码,若是业务逻辑发生了改变,须要四处修改
      • 使用工厂模式统一建立,则只要修改工厂类便可,下降成本

提示:工厂模式适合复杂对象的建立markdown

2、工厂模式代码实现

一、简单工厂模式

简单工厂能够根据不一样参数返回不一样类的实例,须要专门定义一个工厂类来负责建立其余类的实例,被建立实例一般都具备共同的父类或接口;简单工厂又称 静态工厂方法,可经过类名直接调用 ,并且只须要传入简单的参数便可。ide

  • 核心组成
    • Factory:工厂类,简单工厂模式的核心,它负责实现建立全部实例的内部逻辑
    • IProduct:抽象产品类,简单工厂模式所建立的全部对象的父类,描述全部实例所共有的公共接口
    • Product:具体产品类,是简单工厂模式的建立目标
  • 实现步骤
    • 建立抽象产品类,里面有产品的抽象方法,由具体的产品类去实现
    • 建立具体产品类,继承【建立抽象产品类】,并实现具体方法
    • 建立工厂类,提供一个静态方法(createXXX)用来生产产品,只须要传入你想要的产品标识(如:产品名称)
  • 优势:将对象的建立和对象自己业务处理分离,能够下降系统的耦合度,使得二者修改起来都相对容易。
  • 缺点:工厂类的职责相对太重,增长新的产品须要修改工厂类的判断逻辑,这一点与开闭原则是相违背的

建立抽象产品类:oop

/** * 抽象产品 * * @author GitLqr */
public interface IPay {
	/** * 下单功能 */
	void order();
}
复制代码

建立具体产品类:微信支付

/** * 具体产品:微信支付 * * @author GitLqr */
public class WechatPay implements IPay {
	@Override
	public void order() {
		System.out.println("微信 下单");
	}
}

/** * 具体产品:支付宝支付 * * @author GitLqr */
public class AliPay implements IPay {
	@Override
	public void order() {
		System.out.println("支付宝 下单");
	}
}
复制代码

建立工厂类:spa

/** * 工厂类 * * @author GitLqr */
public class PayFactory {
	/** * 根据参数 返回对应的支付对象 */
	public static IPay createPay(String payType) {
		switch (payType) {
		case "alipay":
			return new AliPay();
		case "wechat":
			return new WechatPay();
		default:
			return null;
		}
	}
}
复制代码

使用:设计

public static void main(String[] args) {
    // 简单工厂
    // IPay pay = PayFactory.createPay("alipay");
    IPay pay = PayFactory.createPay("wechat");
    pay.order();
}
复制代码

二、工厂方法模式

工厂方法又称 工厂模式,是对简单工厂模式的进一步抽象化,其好处是可使系统在不修改原来代码的状况下引进新的产品,即知足开闭原则。经过工厂父类定义负责建立产品的公共接口,经过子类来肯定所须要建立的类型。code

  • 核心组成
    • IProduct:抽象产品类,描述全部实例所共有的公共接口
    • Product:具体产品类,实现抽象产品类的接口
    • IFactory:抽象工厂类,描述具体工厂的公共接口
    • Factory:具体工厂类,实现抽象工厂类的接口,建立具体产品对象
  • 优势:
    • 相比简单工厂而言,工厂方法具备更多的可扩展性和复用性,同时也加强了代码的可读性
    • 将类的实例化(具体产品的建立)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化哪个类
    • 符合开闭原则,增长一个产品类,只须要实现其余具体的产品类和具体的工厂类
    • 符合单一职责原则,每一个工厂只负责生产对应的产品
    • 使用者只须要知道产品的抽象类,无须关心产品的具体实现类,知足迪米特法则、依赖倒置原则和里氏替换原则
  • 缺点:
    • 每一个产品须要有对应的具体工厂和具体产品类,即每增长一个产品,都至少会增长 2 个类
    • 使用者必须知道具体的工厂实现类

建立抽象工厂类:orm

/** * 抽象工厂类 * * @author GitLqr */
public interface IPayFactory {
	public IPay getPay();
}
复制代码

建立具体工厂类:

/** * 具体工厂类:建立 支付宝支付 对象 * * @author GitLqr */
public class AliPayFactory implements IPayFactory {
	@Override
	public IPay getPay() {
		return new AliPay();
	}
}

/** * 具体工厂类:建立 微信支付 对象 * * @author GitLqr */
public class WechatPayFactory implements IPayFactory {
	@Override
	public IPay getPay() {
		return new WechatPay();
	}
}
复制代码

使用:

public static void main(String[] args) {
    // 工厂方法
    // IPayFactory payFactory = new AliPayFactory();
    IPayFactory payFactory = new WechatPayFactory();
    payFactory.getPay().order();
}
复制代码

补充:若是后续须要增长第三种支付方式,好比银联支付,那么只须要再扩展出具体产品 UnionPay,以及具体工厂 UnionPayFactory 便可,而无需改动原有的类。

三、抽象工厂模式

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

  • 背景:
    • 工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题
    • 但工厂方法模式中每一个工厂只建立一类具体产品类的对象,后续发展可能会致使工厂类过多,所以将一些相关的具体类组成一个”具体类族“,由同一个工厂来统一辈子产,强调的是一系列相关的产品对象!!
  • 优势:
    • 当一个产品族中的多个对象被设计成一块儿工做时,它能保证使用方始终只使用一个产品族中的对象
  • 缺点:
    • 产品族扩展困难,要增长一个系列的某一产品,既要在抽象工厂和超级工厂类里修改代码,不是很符合开闭原则
    • 增长了系统的抽象性和理解难度

补充:当抽象工厂模式中每个具体工厂类只建立一个产品对象时,抽象工厂模式退化成工厂方法模式。

1)推导过程(工厂方法 --> 抽象工厂 )

假设 "产品" 如今不仅有 支付,还须要有 退款,提现 等,这时,"产品" 的【抽象产品类】和【具体产品类】将拓展为以下所示:

支付(IPay) 退款(IRefund) 提现(ICashout)
支付宝 AliPay AliRefund AliCashout
微信 WechatPay WechatRefund WechatCashout
银联 UnionPay UnionRefund UnionCashout

根据 工厂方法模式 的核心要求(一种工厂 对应生成 一种产品),那么对应的【抽象工厂类】和【具体工厂类】将拓展为以下所示:

支付(IPayFactory) 退款(IRefundFactory) 提现(ICashoutFactory)
支付宝 AliPayFactory AliRefundFactory AliCashoutFactory
微信 WechatPayFactory WechatRefundFactory WechatCashoutFactory
银联 UnionPayFactory UnionRefundFactory UnionCashoutFactory

这时就会发现,严格按照工厂方法模式的要求会有以下弊端:

  1. 工厂类太多了,总体感受工程文件数量很冗余
  2. 对使用者不友好,须要知道的 "工厂" 有点多

其实这些 "产品"(支付、退款、提现...)都是属于一类(订单相关), 所以,能够对【抽象工厂类】进行加强,由一个【抽象工厂类】来负责生产一类 "产品",例如能够建立 IOrderFactory,汇总 IPayFactory、IRefundFactory、ICashoutFactory 的建立方法并对它们进行取缔。因而,使用了抽象工厂模式后,对应的【抽象工厂类】和【具体工厂类】将拓展为以下所示:

支付、退款、提现(IOrderFactory)
支付宝 AliOrderFactory
微信 WechatOrderFactory
银联 UnionOrderFactory

注意:抽象工厂 相比 工厂方法,就是加强了抽象工厂类,同时思想上也有了重大变化,让抽象工厂类再也不局限于一种产品,而是一系列产品。

2)代码实现

建立抽象产品类:

/** * 抽象产品 * * @author GitLqr */
public interface IRefund {
	/** * 退款 */
	void refund();
}
复制代码

建立具体产品类:

/** * 具体产品:支付宝退款 * * @author GitLqr */
public class AliRefund implements IRefund {
	@Override
	public void refund() {
		System.out.println("支付宝 退款");
	}
}
/** * 具体产品:微信退款 * * @author GitLqr */
public class WechatRefund implements IRefund {
	@Override
	public void refund() {
		System.out.println("微信 退款");
	}
}
复制代码

建立抽象工厂类【加强版】:

/** * 抽象工厂类【加强版】 * * @author GitLqr */
public interface IOrderFactory {
	IPay getPay();

	IRefund getRefund();
}
复制代码

建立具体工厂类【加强版】:

/** * 具体工厂类:建立 支付宝 订单相关的一系列产品功能 * * @author GitLqr */
public class AliOrderFactory implements IOrderFactory {
	@Override
	public IPay getPay() {
		return new AliPay();
	}

	@Override
	public IRefund getRefund() {
		return new AliRefund();
	}
}
/** * 具体工厂类:建立 微信 订单相关的一系列产品功能 * * @author GitLqr */
public class WechatOrderFactory implements IOrderFactory {
	@Override
	public IPay getPay() {
		return new WechatPay();
	}

	@Override
	public IRefund getRefund() {
		return new WechatRefund();
	}
}
复制代码

还能够借鉴简单工厂模式,建立一个"超级工厂类",根据不一样参数获取不一样的具体工厂,方便使用者使用:

public class OrderFactoryProducer {

	public static IOrderFactory getFactory(String type) {
		switch (type) {
		case "alipay":
			return new AliOrderFactory();
		case "wechat":
			return new WechatOrderFactory();
		default:
			return null;
		}
	}
}
复制代码

说明:【简单工厂模式】的最大缺点就是负责了全部具体产品的建立,而这里则不一样,具体产品的建立已交由具体工厂去建立,"超级工厂类" 只负责找到合适的具体工厂,与产品没有直接关系。固然,”超级工厂类“这种方式方式仍是不符合开闭原则的,需本身权衡利弊,我的感受至少比让使用者直接使用具体工厂要好控制一些。

使用:

public static void main(String[] args) {
    // 抽象工厂
    // IOrderFactory orderFactory = OrderFactoryProducer.getFactory("alipay");
    IOrderFactory orderFactory = OrderFactoryProducer.getFactory("wechat");
    orderFactory.getPay().order();
    orderFactory.getRefund().refund();
}
复制代码

若是文章对您有所帮助, 请不吝点击关注一下个人微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不只有Android技术, 还有iOS, Python等文章, 可能有你想要了解的技能知识点哦~

相关文章
相关标签/搜索