设计模式之工厂模式

老铁们,我们今天来说说工厂模式。

0. 前言

一般来讲,工厂模式分3种,分别是:简单工厂模式、工厂方法模式以及抽象工厂模式。由于这几种容易混淆,我们放在一起聊聊。

其实,任何可以产生对象的方法或者类,都可以叫做工厂。换句话说,工厂模式就是把以前通过new产生对象的方式变为通过工厂取得。

为什么要有工厂模式,直接通过new创建对象不行吗?

我们说,也可以。但是,把创建对象的过程抽取出来,能够灵活控制对象生产过程,例如在其中增加一些单例控制,或者权限、日志之类的其他处理,这些需求都可以交给工厂去实现,方便解耦

当然了,有人说了,我这只需要简单new出来一个对象,其他也用不到,那可以不用设计模式。总之,设计模式是让系统变得更简单,而不更是复杂

1. 简单工厂模式

我们暂且从一个简单的类开始吧。

现在有个简单的Bread类。

Bread.java

public class Bread{
 void eat() {
  System.out.println("冷风在北京 eat bread");
 }
}

那现在要吃面包,怎么办?没问题,new一个Bread对象,然后调用eat方法。

Client.java

public class Client {
 public static void main(String[] args) {
    Bread b = new Bread();
    b.eat();
  }
}

有一天面包吃腻了,想吃饺子,那我们就建个“饺子”对象。

Dumplings.java

public class Dumplings{
 void eat() {
  System.out.println("冷风在北京 eat Dumplings");
 }
}

然后再修改客户端:

Client.java

public class Client {
 public static void main(String[] args) {
    Dumplings d = new Dumplings();
    d.eat();
  }
}

假设到某一天,饺子也吃腻了,想吃.........。你会发现,客户端每次都需要改代码,new出来相应的类。那能不能 “坐享其成”,给工厂传个参数,或者调用一个工厂方法,就能生成想要的对象。

工厂模式就是来解决这个问题的。

我们先抽象出一个Food类,Bread和Dumplings去继承。

 

Food.java

public abstract class Food {
   abstract void eat();
}

Bread.java

public class Bread extends Food{
 @Override
 void eat() {
    System.out.println("冷风在北京 eat bread");
 }
}

Dumplings.java

public class Dumplings extends Food{
 @Override
 void eat() {
    System.out.println("冷风在北京 eat Dumplings");
 }
}

此时,再创建一个简单工厂类,去生产我们需要的具体产品

SimpleFoodFactory.java

public class SimpleFoodFactory {
 //简单工厂, 通过传入参数或者直接用方法来区分,以实现不同的对象返回.可扩展性不太好,如果要吃点别的.
 Food makeBread(){
      //doSth();其他处理
    return new Bread();
 }
 Food makeDumplings(){
    //doSth();其他处理
    return new Dumplings();
 }
}

客户端的调用修改为:

Client.java

public class Client {
 public static void main(String[] args) {
    SimpleFoodFactory ff = new SimpleFoodFactory();
    Food f = ff.makeDumplings();
    f.eat();
  }
}

这样,只需要去调用SimpleFoodFactory的makeBread或者makeDumplings方法,就能取到需要的对象了。

小结一下

简单工厂其实就是将各个对象的创建过程封装了起来,需要对象时,直接调用方法去拿。

简单工厂模式的要素:

  • 一个抽象类或者接口(Food)

  • 几个具体的实现类(Bread、Dumplings)

  • 一个简单工厂类(SimpleFoodFactory)

优点:将创建对象的逻辑封装起来,便于解耦。

缺点:扩展性不好,当增加其他具体的Food类型时,需要修改SimpleFoodFactory类,增加makeXXX方法。

2. 工厂方法模式

鉴于简单工厂不好扩展的问题,就出现了工厂方法模式。该模式下,我们不再像简单工厂那样去传参数或者调用方法去创建不同的对象,而是将每一个具体的产品都创建一个工厂,即面包有面包的工厂,饺子有饺子的工厂。

BreadFactory.java

public class BreadFactory {
 //工厂方法;将具体的产品交给具体的工厂来实现,扩展性变好
 Bread makeBread(){
    return new Bread();
 }
}

DumplingsFactory.java

public class DumplingsFactory {
 //工厂方法;将具体的产品交给具体的工厂来实现,扩展性变好
 Dumplings makeDumplings(){
  return new Dumplings();
 }
}

此时,调用方修改为:

  //Food f1 = new BreadFactory().makeBread();
 Food f2 = new DumplingsFactory().makeDumplings();
 f2.eat();

这样,扩展起来就方便多了,如果增加Cookie,只需要增加Cookie类和CookieFactory即可,而不像简单工厂模式,需要修改工厂类了。

工厂模式的要素:

  • 一个抽象类或者接口(Food)

  • 几个具体的实现类(Bread、Dumplings)

  • 多个具体工厂类(DumplingsFactory)

 

如果需要扩展时,只需要新建具体产品和具体工厂类即可。

3. 抽象工厂模式

上面说的都是具体的工厂类,那为什么还需要抽象工厂呢?

我们来考虑这样一个问题,现在不光是吃面包和饺子的问题了,吃完了还得喝点啥。像Food一样,我们先扩展出一个Drink抽象类。

Drink.java

public abstract class Drink {
   abstract void drink();
}

CocaCola.java

public class CocaCola extends Drink{
 @Override
 void drink() {
    System.out.println("冷风在北京 drink cocacola");
 }
}

Soup.java

public class Soup extends Drink{
 @Override
 void drink() {
    System.out.println("冷风在北京 drink Soup");
 }
}

这时,在工厂模式的基础上,我们再向上抽象一层,抽象出抽象工厂类。抽象工厂类包括了eat()和dirnk()方法。

AbstractFactory.java

public abstract class AbstractFactory {
 abstract Food makeFood();
 abstract Drink makeDrink();
}

现在有个美国人和中国人,那美国人的习惯和中国人肯定不一样。 我们建2个具体工厂,来继承抽象工厂。

AmericanFactory.java

public class AmericanFactory extends AbstractFactory{
 @Override
 Food makeFood() {
  return new Bread();
 }
 @Override
 Drink makeDrink() {
  return new CocaCola();
 }
}

ChineseFactory.java

public class ChineseFactory extends AbstractFactory{
 @Override
 Food makeFood() {
  return new Dumplings();
 }
 @Override
 Drink makeDrink() {
  return new Soup();
 }
}

类图就变成了这个样子。

 

所以说,顾名思义,抽象工厂可以理解为只生产抽象的一组产品(吃的、喝的)。下面有具体的产品工厂去继承抽象工厂,生产更具体的一系列产品。美国工厂生产可乐和面包,中国工厂生产饺子和汤。假设后面又出现了印度工厂(假设印度人吃咖喱,喝水实在不知道阿三喝啥了),我们只需要三个具体类:

  • IndianFactory extends AbstractFactory

  • Curry extends Food

  • Water extends Drink

相比于前两种模式,抽象工厂模式增加了抽象工厂这一个要素,共有四个角色:

  • 抽象工厂(吃的、喝的)

  • 具体工厂 (中国工厂,美国工厂等)

  • 抽象产品 (吃的,喝的)

  • 具体产品 (面包,可乐,饺子,汤)

看得出来,抽象工厂是从一个产品组的角度去看问题的,而工厂方法和简单工厂只关注于具体产品本身。即抽象工厂要和多类产品打交道,而工厂方法和简单工厂只和具体某个产品联系。

总结

我们说,上述三种模式,没有哪个最好,只有谁更适合什么场景。

  • 简单工厂模式

优点:将创建对象的逻辑封装起来,便于解耦。

缺点:不方便扩展。当需要一个新的类型时,需要修改工厂类。

适用场景:业务简单,产品较少,且不易变化的场景。

  • 工厂方法模式

优点:方便扩展,每增加一个具体类,只需要增加工厂即可。

缺点:当产品较多时,增加代码较多。

适用场景:产品有限扩展的情况。

  • 抽象工厂

优点:相比前两种,更适宜去管理一系列的产品,在产品系列方向比较容易扩展。

应用场景:产品系列管理。

最后,我们再来理解一下这三种模式。

简单工厂模式首先将创建对象的过程封装了起来,其中可以增加一些过程上的控制,例如单例、权限之类的。客户端不用关心对象的创建过程,只需要上送要创建的对象名称即可。但是由于简单工厂扩展时需要修改工厂类,所以又出现了工厂模式。

在工厂模式下,为了便于扩展,所以将每个具体的产品都建一个工厂类。

而出于对产品组合管理的需求,又出现了抽象工厂模式。

抽象工厂的关注点在于产品组合(吃的+喝的),更像是去做一件完整的事情,将诸多产品去有机组织起来。而工厂方法和简单工厂比较简单,只用来生产具体产品。

好了,工厂模式就先分享到这儿,希望能对各位小伙伴有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷风在北京

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值