工厂模式
简介
在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。
但是在一些情况下, new操作符直接生成对象会带来一些问题。
举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。 在这些情况,新对象的建立就是一个 “过程”,不仅是一个操作,像一部大机器中的一个齿轮传动。
模式的问题:你如何能轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程呢?
解决方案:建立一个工厂来创建对象
工厂模式
分类
工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
工厂模式可以分为三类:
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。
GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
1.没有工厂时:假如还没有工业革命,如果一个客户要一款电脑,一般的做法是客户去创建一款电脑,然后拿来用。
2.简单工厂模式:后来出现工业革命。用户不用去创建电脑。因为客户有一个工厂来帮他创建电脑.想要什么牌子的电脑,这个工厂就可以建。比如想要神舟战神电脑。工厂就创建这个系列的电脑。即工厂可以创建产品。
3.工厂方法模式:为了满足客户,电脑系列越来越多,如外星人,DELL,ThinkPad,Mac等系列。一个工厂无法创建所有品牌的电脑,于是由单独分出来多个具体的工厂。每个具体工厂创建一种品牌的电脑。即具体工厂类只能创建一个具体产品。但是电脑工厂还是个抽象。你需要指定某个具体的工厂才能生产电脑出来。比如我要Mac,就需要去找生产Mac电脑的苹果工厂。
4.抽象工厂模式:随着客户的要求越来越高,电脑必须配置十代i7CPU。于是这个工厂开始生产十代i7CPU。
最终是客户只要对电脑的销售员说:我要一台十代i7CPU的Mac,那销售就直接给客户十代i7CPU的Mac。而不用自己去创建十代i7CPU的Mac.
这就是工厂模式。
简单工厂模式
建立一个工厂(一个函数或一个类方法)来制造新的对象。
从无到有。客户自己创建电脑,然后拿来用。
public class Mac {
public Mac(){
System.out.println("制造-->Mac");
}
}
public class Dell {
public BMW523(){
System.out.println("制造-->DELL");
}
}
public class Customer {
public static void main(String[] args) {
Mac mac = new Mac();
DELL dell = new DELL();
}
}
客户需要知道怎么去创建一款电脑,客户和电脑就紧密耦合在一起了。为了降低耦合,就出现了工厂类。
把创建电脑的操作细节都放到工厂里面去,客户直接使用工厂的创建工厂方法,传入想要的电脑品牌就行了,而不必去知道创建的细节.这就是工业革命了:简单工厂模式
即我们建立一个工厂类方法来制造新的对象。如图:

/*
* 产品类
*/
abstract class Computer {
public Computer(){
}
}
public class Mac extends Computer {
public Mac() {
System.out.println("制造-->Mac");
}
}
public class Dell extends Computer{
public Dell(){
System.out.println("制造-->Dell");
}
}
/*
* 工厂类
*/
public class Factory {
public Computer create(int type) {
switch (type) {
case 1:
return new Mac();
case 2:
return new Dell();
default:
break;
}
return null;
}
}
使用工厂:
Factory factory = new Factory();
Mac mac = factory.create(1);
Dell dell = factory.create(2);
简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。
它存在的目的很简单:定义一个用于创建对象的接口。
先来看看它的组成:
- 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
- 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
- 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。
当客户不再满足现有的电脑品牌的时候,想要另外一种电脑的时候,只要这种电脑符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的。
但是工厂部分好像不太理想,因为每增加一种新型电脑,都要在工厂类中增加相应的创建业务逻辑(create(int type)方法需要新增case),这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。
于是工厂方法模式作为救世主出现了。 工厂类定义成了接口,而每新增的电脑品牌,就增加该品牌电脑对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码。
工厂方法模式
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
工厂方法模式组成:
- 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
- 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
- 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
- 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。可以看出工厂角色的结构也是符合开闭原则的!
代码如下:
/*
* 产品类
*/
abstract class Computer {
public Computer(){
}
}
public class Mac extends Computer {
public Mac() {
System.out.println("制造-->Mac");
}
}
public class Dell extends Computer{
public DELL(){
System.out.println("制造-->Dell");
}
}
/*
* 工厂类
*/
interface Factory {
Computer create();
}
public class MacFactory implements Factory{
@Override
public Mac create() {
return new Mac();
}
}
public class DellFactory implements Factory {
@Override
public DELL create() {
return new Dell();
}
}
使用工厂:
Factory macFactory = new MacFactory();
Mac mac = macFactory.create();
Factory factory523 = new DellFactory();
Dell dell = factory523.create();
工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口。
但这使得对象的数量成倍增长,当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。
抽象工厂模式
抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。
在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如Mac电脑使用十代i7CPU和1TSSD,而Dell电脑i5CPU和2TSSD,那么使用抽象工厂模式,在为Mac电脑生产相关配件时,就无需制定配件的型号,它会自动根据电脑品牌生产对应的配件型号A。
当每个抽象产品都有多于一个的具体子类的时候(CPU有A和B两种,SSD也有A和B两种),工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品(产品CPU有两个具体产品CPUA和B)。抽象工厂模式提供两个具体工厂角色(Mac工厂和Dell工厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。
/*
* 产品类
*/
//CPU
public abstract Cpu {
}
public class CpuA extends Cpu{
public CpuA(){
System.out.println("制造-->i7Cpu");
}
}
public class CpuB extends Cpu{
public CpuB(){
System.out.println("制造-->i5Cpu");
}
}
//SSD
public abstract SSD {
}
public class SSDA extends Aircondition{
public SSDA(){
System.out.println("制造-->SSDA 1T");
}
}
public class SSDB extends Aircondition{
public SSDB(){
System.out.println("制造-->SSDB 2T");
}
}
/*
* 产品类
*/
//创建工厂的接口
public interface AbstractFactory {
//制造发动机
public CPU createCpu();
//制造空调
public SSD createSSD();
}
//为Mac生产配件
public class MacFactory implements AbstractFactory{
@Override
public Cpu createCpu() {
return new CpuA();
}
@Override
public SSD createSSD() {
return new SSDA();
}
}
//为Dell生产配件
public class DellFactory implements AbstractFactory {
@Override
public Cpu createCpu() {
return new CpuB();
}
@Override
public SSD createSSD() {
return new SSDB();
}
}
使用抽象工厂模式:
//为Mac生产配件
AbstractFactory macFactory = new MacFactory();
macFactory.createCpu();
macFactory.createSSD();
//为Dell生产配件
AbstractFactory dellFactory = new DellFactory();
dellFactory.createCpu();
dellFactory.createSSD();
区别
工厂方法模式:
- 一个抽象产品类,可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
- 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类可以创建多个具体产品类的实例。
区别:
- 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
- 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
总结
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。
在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

浙公网安备 33010602011771号