Java设计模式 | 工厂方法模式

前言

上一篇文章我们讲了简单工厂模式,拿了商店提供产品做例子,我们向商店说明要什么产品,商店就提供我们什么产品。

使用简单工厂模式时,实现的商店(工厂类)是这样的。

/**
 * 洗护产品店
 *
 * @author dashu
 * @since 2021/8/2
 */
public class HygieneProductStore {
    public static HygieneProduct offer(HygieneProductEnum hygieneProduct) {
        if (HygieneProductEnum.SHAMPOO.equals(hygieneProduct)) {
            return new Shampoo();
        } else if (HygieneProductEnum.BODY_WASH.equals(hygieneProduct)){
            return new BodyWash();
        } else {
            throw new UnsupportedOperationException("本店暂不卖这类产品");
        }
    }
}

这里商店的offer方法,我们指定洗发水,商店就创建洗发水给我们,我们指定沐浴露,商店就创建沐浴露对象给我们。

简单工厂模式基本实现了将对象的生产和使用分离。

但是这里有一个缺陷。目前商店只提供洗发水和沐浴露,如果某一天,商店准备增供
【防晒霜】呢?

那就加多一个【防晒霜】的具体产品类,并且在商店的offer方法中多加一个else,创建【防晒霜】对象。

如果之后又添加【洗手液】【护发素】等等洗护产品呢,当然,可以继续新建产品类,继续往商店的offer方法中添加else,这样做是可以实现我们的功能的。

但是如果这些产品经常变动,经常增加或者删减,你会发现,使用简单工厂模式的话,就得反复修改工厂类。每变动一次,我们就不得不修改工厂类一次。

这样子频繁修改同一个类的一个方法,是很容易改出问题的。我们的示例还是比较简单的,直接就new了,如果工厂生产对象的逻辑比较复杂呢。

软件设计中有一个“开闭原则”,对拓展开放,对修改关闭,这种反复修改offer方法的行为就违背了开闭原则。

如果我们的产品的种类基本不变或者很少改变,那么简单工厂模式是够用了,但是如果产品种类经常变化,那么我们应该引入工厂方法模式 ---- 简单工厂模式的升级版。

1. 定义

工厂方法模式又称为工厂模式,虚拟构造器模式或者多态工厂模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,工厂子类负责创建具体产品,将产品类的实例化延迟到了工厂子类中完成。

2. 模式结构

组成

  • 抽象产品
  • 具体产品
  • 抽象工厂
  • 具体工厂

工厂方法模式跟简单工厂模式对比,工厂类有了一个抽象的工厂。

3. 代码示例

工厂方法模式实现洗护产品店卖洗护产品是这样子的。

  • 有一个抽象的产品 ---- 洗护产品。
  • 有一些具体的产品类 ---- 洗发水、沐浴露。
  • 有一个抽象工厂,定义了一个offer(提供产品)方法,实现逻辑是,你想要洗发水,我就让洗发水专区提供一瓶洗发水给你,你想要沐浴露,我就让沐浴露专区提供沐浴露给你。
  • 还有一些具体的工厂继承自抽象工厂,比如洗发水专区(具体工厂),沐浴露专区(具体工厂)。

如果我之后想要加入【防晒霜】产品,那么就新建一个【防晒霜】类(新的具体产品),新建一个【防晒霜】专区(新的具体工厂)。

如果我之后想要移除【洗发水】产品,那么就删掉【洗发水】类(已有的具体产品),删除【洗发水】专区(已有的具体工厂)。

看,这样子,但是无论新增产品还是删除产品,都不会动到抽象工厂生产产品的逻辑。

新增产品时,只需要关注新产品,删除产品时,只需要关注删除的产品,不用担心影响到其他的产品。

------------------------------------------------------代码示例----------------------------------------------------------
抽象产品

/**
 * 洗护产品
 * 
 * @author dashu
 * @since 2021/8/20
 */
public abstract class HygieneProduct {
	public abstract void whoAmI();
}

具体产品

/**
 * 洗发水
 * 
 * @author dashu
 * @since 2021/8/20
 */
public class Shampoo extends HygieneProduct {
	public void whoAmI() {
		System.out.println("我是洗发水");
	}
}
/**
 * 沐浴露
 * 
 * @author dashu
 * @since 2021/8/20
 */
public class BodyWash extends HygieneProduct {
	public void whoAmI() {
		System.out.println("我是沐浴露");
	}
}

抽象工厂

/**
 * 洗护产品店
 *
 * @author dashu
 * @since 2021/8/23
 */
public abstract class HygieneProductStore {
    public abstract HygieneProduct offer();
}

具体工厂

/**
 * 洗发水专区
 *
 * @author dashu
 * @since 2021/8/23
 */
public class ShampooArea extends HygieneProductStore {
    @Override
    public HygieneProduct offer() {
        return new Shampoo();
    }
}
/**
 * 沐浴露专区
 *
 * @author dashu
 * @since 2021/8/23
 */
public class BodyWashArea extends HygieneProductStore {
    @Override
    public HygieneProduct offer() {
        return new BodyWash();
    }
}

客户端

/**
 * 客户端
 * 
 * @author dashu
 * @since 2021/8/23
 */
public class Client {
    public static void main(String[] args) {
        ShampooArea shampooArea = new ShampooArea();
        HygieneProduct shampoo = shampooArea.offer();
        shampoo.whoAmI();

        BodyWashArea bodyWashArea = new BodyWashArea();
        HygieneProduct bodyWash = bodyWashArea.offer();
        bodyWash.whoAmI();
    }
}
4. 模式优缺点
优点
  1. 工厂方法用来创建客户端需要的产品,又向客户端隐藏了具体产品类实例化的细节。用户只需要关心产品对应的工厂即可,无需关心具体产品类名和创建细节。
  2. 工厂可以自主确定创建什么产品,如何创建的细节都是完全封装在具体工厂内部的。
  3. 在加入新产品时,无需修改客户端,无需修改抽象工厂,也无需修改其他的具体工厂和具体产品,只需要增加一个新的具体工厂和具体产品。
缺点
  1. 需要增加一个产品时,就要新增一个对应的工厂,每次新增都是成对新增,一定程度增加了系统的复杂度。
  2. 引入了抽象层,增加了系统的抽象性和理解难度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值