2.设计模式之抽象工厂模式笔记

1.简单工厂模式

考虑这样一个需求:
有一个CoffeeStore可以提供Coffee;有一个Coffee接口,有AmericanCoffee和LatteCoffee两个具体的实现类.在一个CoffeeStore内,有orderCoffee(String type)这样一个方法,需要根据传入的类型,来确定返回的具体coffee类型,那么在你的客户端代码中可能会有这样的代码:

 Coffee coffee = null;
    if("americano".equals(type)) {
      coffee = new AmericanoCoffee();
   } else if("latte".equals(type)) {
      coffee = new LatteCoffee();
   }
    return coffee;

类图结构:
在这里插入图片描述

但是这样的代码,灵活性很差,违反了"开闭原则".
可以将创建一个新的SimpleFactory,工厂里提供一个工厂方法,提供创建Coffee的工厂方法:

public class SimpleCoffeeFactory {
  public Coffee createCoffee(String type) {
    Coffee coffee = null;
    if("americano".equals(type)) {
      coffee = new AmericanoCoffee();
   } else if("latte".equals(type)) {
      coffee = new LatteCoffee();
   }
    return coffee;
 }
}

类图结构:
在这里插入图片描述

然后在你的客户端代码创建简单工厂对象来调用方法创建对象.或者将这个工厂方法定义成static的,直接通过类名来调用createCoffee()方法来创建coffee对象(这种叫静态工厂,静态工厂不能通过继承来重载工厂方法).

这么做有什么好处,似乎只是把问题搬到了另一个地方罢了?
1.如果在客户端很多地方调用了SimpleFactory方法来创建Coffee对象,一旦创建Coffee对象的逻辑改变了,你只需要修改SimpleFactory这个工厂类的代码就可以了.如果将那些判断的逻辑写在了客户端代码中,就需要所有创建Coffee对象的代码了.
2.它实现了客户端代码和Coffee对象的解耦合.客户端只需要知道调用工厂方法产生一个Coffee对象,它不在需要知道这个对象具体怎么实现.这个对象的实现被"封装"在了工厂类里.具体怎么产生于客户端无关了.

简单工厂不是一个设计模式,更像是一种编程习惯.但是它确实能带来很多好处.但是缺点也很明显,当我们想要增加一种coffee类型的时候,就需要修改simpleFactory的代码逻辑,违背"开闭原则".

2.工厂方法模式

针对上面简单工厂的问题,可以通过工厂方法模式来解决,实现开闭原则.

工厂方法模式的定义:

定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法让一个类的实例化延迟到其工厂的子类.

工厂方法模式有四个角色:
抽象工厂:提供了创建产品的接口(方法),调用者通过它访问具体工厂的工厂方法来创建产品。
具体工厂:实现抽象工厂的中的抽象方法,完成具体产品的创建.
抽象产品:定义了产品的规范,描述了产品的特性和功能.就是工厂方法所创建的对象的接口.
具体产品:实现了抽象产品所定义的接口,由具体的工厂创建.

类图如下:
在这里插入图片描述抽象工厂CoffeeFactory,提供了创建产品的方法createCoffee(),返回工厂生产的抽象产品Coffee.

public interface CoffeeFactory {
  Coffee createCoffee();
}

具体工厂AmericanCoffeeFactory,实现抽象工厂中的createCoffee(),返回具体的产品AmericanCoffee,LatteCoffee.

public class LatteCoffeeFactory implements CoffeeFactory {
  public Coffee createCoffee() {
    return new LatteCoffee();
 }
}


public class AmericanCoffeeFactory implements CoffeeFactory {
  public Coffee createCoffee() {
    return new AmericanCoffee();
 }

现在回头理解一下工厂方法模式定义.

对于简单工厂的违反开闭原则,工厂方法完美解决.现在如果需要另外一种类型的BlueMountainCoffee,只需要定义一个BlueMountainCoffeeFactory,返回具体的BlueMountainCoffee即可.在不改变原有代码基础上实现扩展.缺点是,一个工厂方法只能生产一种具体的Coffee,如果很有多类型Coffee,就会有很多对应的Factory,类爆炸问题.

工厂方法的一个具体应用:
ArrayList类
类结构图:
在这里插入图片描述
在ArrayList源码中的位置:
在这里插入图片描述
ArrayList的内部类Itr(具体产品)实现了Iterator接口(抽象产品).ArrayList(具体工厂)实现Collection接口(抽象工厂)的iterator()(工厂方法),返回具体产品Itr.

3. 抽象工厂模式

前面工厂方法模式中考虑的是一类产品的生产,如电视机厂只生产电视机,咖啡店只生产咖啡.这些工厂只生产同种类产品,同种类产品称为同等级产品,也就是说,工厂方法只生产同等级产品.AmericanCoffeeFactory和LatteCoffeeFactory生产的都是Coffee这个产品.但是现实生活中,很多工厂都是综合性的工厂,如小米工厂即可以生产小米手机,还可生产小米电视,小米笔记本.这属于同一个产品族的不同等级产品.

抽象工厂模式将考虑多等级产品的生产.将一个工厂生产的位于不同等级的产品称为一个产品族.
在这里插入图片描述
抽象工厂的概念:

提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类.

注意,这个接口内地额方法不是任意的,而是一系列相关或者相互依赖的方法.(即生产的产品是同一个产品族.)
抽象工厂的主要角色:
抽象工厂:提供创建产品的接口,他有多个创建产品的方法,可以创建不同等级的产品.
具体工厂:实现抽象工厂的方法,完成具体产品的创建.
抽象产品:定义了产品的规范,描述了产品的主要特性和功能.抽象工厂有多个抽象产品.
具体产品:实现了抽象产品所定义的接口,由具体工厂来创建,他和具体工厂之间的关系是多对一的关系.

对于上面的案例,现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点,如提拉米苏、抹茶慕斯等,要是按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况。其中拿铁咖啡、美式咖啡是一个产品等级,都是咖啡;提拉米苏、抹茶慕斯也是一个产品等级;拿铁咖啡和提拉米苏是同一产品族(也就是都属于意大利风味),美式咖啡和抹茶慕斯是同一产品族(也就是都属于美式风味)。所以这个案例可以使用抽象工厂模式实现。类图如下:

在这里插入图片描述
抽象工厂DessertFactory提供了生产Coffee和Dessert两个抽象产品的接口,AmericanDessertFactory和ItalyDessertFactory这两个具体工厂实现了抽象工厂的接口,分别生产具体产品AmericanCoffee,MatchaMousse和LatteCoffee,Tiramisu.注意AmericanDessertFactory生产的都属于美式风味(产品族),ItalyDessertFactory生产都是意大利风味.

抽象工厂的优点:当一个产品族的多个产品被设计在一起工作时,它能保证客户端只使用同一产品族中的对象.
缺点:当抽象工厂的产品族要添加一个新等级的产品时,所有的工厂类(具体工厂)都要修改.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值