抽象工厂学习

Posted Jason.Zeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了抽象工厂学习相关的知识,希望对你有一定的参考价值。

作者:caoglish
链接:https://www.zhihu.com/question/20367734/answer/82361745
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

今天正好在学习抽象工厂和工厂方式,我就把我的理解写一写。

工厂一般理解就是减少new创建对象的方式,用接口的方式来返回一个对象,而new创建的方式被封装了。然而,这个是初级认识,这不足以理解到工厂方式的真正目的。

所以我要用我的方式帮助大家理解。

第一部分: 抽象工厂
一般来说,抽象工厂最简单形态也至少有4个元素:
  • 客户端(client)
  • 工厂(factory)
  • 产品A(product A)
  • 产品B(product B)

我先用一个例子来实体说明抽象工厂是什么
技术分享
我现在有三个神枪手,他们聚在一起讨论他们玩枪的经历,
  • 神枪手1:AK47打枪最好,杀伤力大。
  • 神枪手2:沙漠之鹰最好,准。
  • 神枪手3:连弩才好,上古兵器。

他们争论相持不下,所以决定比试一下,然后约定一个月后来鄙视。然后我们看到三个人分别去各自的工厂去购买武器。


神射手1 去了AK47工厂,购买他们生产的武器和子弹

技术分享

神射手2 去了沙漠之鹰工厂,购买他们生产的武器和子弹

技术分享

神射手3,去了连弩工厂,购买他们生产的武器和“子弹”


技术分享

一个月后,我们看到了3个人分别拿出来以下的武器组合


技术分享

这三个人虽然用的武器不一样,但是每件武器都要做两件事技术分享


最后,他们通过比赛谁,看哪种武器是最优秀的。


我们回头去看看,发现虽然三个人去了不同的工厂,用了不同的武器,用了不同的子弹,但是他们的相似之处太多,可以抽象出来。抽象出来的关系框架就是抽象工厂模式

  • 武器工厂生产武器
  • 武器工厂生产武器所用的子弹
  • 武器可以装载子弹
  • 武器可以射击子弹
  • 神射手装载子弹
  • 神射手射击子弹

那么把关系画出来就是:

技术分享

然后抽象一下成工厂模式就是:

技术分享

图画出来了,然后我们要如何理解抽象工厂模式. 过去人们都是从工厂开始解释,其实我个人觉得,倒过来讲反而更好理解。而理解抽象工厂模式的关键在于如何理解“产品之间特定关系”。

  1. 用户要调用产品之间的这个特定关系
  2. 这个特定关系只有产品A和产品B之间才有,所以我们需要产品A和产品B
  3. 要获得产品A和产品B,我们要去生产这个产品A和产品B的那个工厂,叫工厂生产这个产品A和产品B

那么用例子来说,就是:

  1. 神枪手喜欢装载子弹和射击的感觉(他们就是喜欢这个,只要有武器符合这个条件就行)
  2. 那么他们就是需要武器(枪或者连弩)和子弹,这个武器是可以装载相应子弹和射击相应子弹的
  3. 他们可以去特定工厂(ak47工厂或者连弩工厂)要求购买武器和相应子弹、

所以理顺抽象工厂的特点是什么?就是如下几个特点:

  • 工厂是独立的(独立的类)
  • 工厂是生产一整套有产品的(至少要生产两个产品),这些产品必须相互是有关系或有依赖的
  • 工厂是可以抽象的,工厂生产是可以抽象的,就是可以建模,用类来模拟
  • 产品是可以抽象的,产品关系是可以抽象的
  • 客户端是用来调用并理顺这些产品之间的关系(或指定工作流程)
  • 不同工厂生产出的产品实例之间是不接触的,这个是靠客户端来封装实现的。
用一个例子来解释一下最后一条“不同工厂生产出的产品实例之间是不接触的,这个是考客户端来封装实现的”。
一个射击学员刚入门,听到射击老师说射击的几个要素: 武器,子弹,武器装载子弹,武器打出子弹。这个学员跃跃欲试,就跑到Ak47工厂买了枪,然后跑到沙漠之鹰工厂买了子弹,AK47装载沙鹰子弹,然后打出。学员卒。

老师听说后,为了避免这个悲剧发生,承包了武器和子弹购买,要用AK47就必须在AK47工厂购买AK47和AK47子弹,保证了AK47加载沙漠之鹰子弹这样的悲剧发生了。
这就是客户端加载工厂实例后,保证只使用这个工厂的生产的产品和产品之间的关系,确保不和其他工厂的产品实例进行接触。

最终当我们调用客户端的行为时候,只要让客户端“加载”实例化的特定工厂,返回结果就是这个“特定工厂”所加工出来的“特定产品”的“特定关系”方法的结果了。


所以,当产品非常多的时候,产品之间关系又非常复杂,但却又可以进行抽象的时候,就是使用抽象工厂模式最好的时候了。

以上就是抽象工厂模式的个人理解


--------

第二部分: 工厂方法


工厂方法就两个元素:

  • creator(创建者)
  • product(产品)

而工厂方法就是一个创建者这个类的一个方法而已,这个方法就是用来封装产品的创建。


第三部分: 抽象工厂 和工厂方法的不同点


我从一下几个方面来理解抽象工厂和工厂方法不同点

  • 抽象工程关键在于产品之间的抽象关系,所以至少要两个产品;工厂方法在于生成产品,不关注产品间的关系,所以可以只生成一个产品。

  • 抽象工厂中客户端把产品的抽象关系理清楚,在最终使用的时候,一般使用客户端(和其接口),产品之间的关系是被封装固定的;而工厂方法是在最终使用的时候,使用产品本身(和其接口)。
抽象工厂更像一个复杂版本的策略模式,策略模式通过更换策略来改变处理方式或者结果;而抽象工厂的客户端,通过更改工厂还改变结果。所以在使用的时候,就使用客户端和更换工厂,而看不到产品本身。

工厂方法目的是生产产品,所以能看到产品,而且还要使用产品。当然,如果产品在创建者内部使用,那么工厂方法就是为了完善创建者,从而可以使用创建者。另外创建者本身是不能更换所生产产品的。


  • 抽象工厂的工厂是类;工厂方法的工厂是方法。
抽象工厂的工厂类就做一件事情生产产品。生产的产品给客户端使用,绝不给自己用。
工厂方法生产产品,可以给系统用,可以给客户端用,也可以自己这个类使用。自己这个类除了这个工厂方法外,还能有其他功能性的方法


其实仔细想想,这个两个模式是有交集的,在极端的情况下,这两个模式其实是一样的。所以可以这样理解
  • 给工厂方法模式加一个客户端,除了客户端都不用这个创建者。这个时候创建者就是工厂类了。(单一产品的特定关系这个时候就是没有关系)
  • 抽象工厂模式中,在客户端内部编程时候,就可以把工厂类当作创建者。






















































以上是关于抽象工厂学习的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式学习记录-抽象工厂模式

java/android 设计模式学习笔记---抽象工厂模式

抽象工厂学习

设计模式学习——简单工厂模式工厂模式抽象工厂模式

学习设计模式之抽象工厂模式

《Head First 设计模式》学习笔记——工厂模式 + 抽象工厂模式