常见的设计模式:工厂模式
设计模式,是一个在面试当中很常听到的词,是一些大佬们在编程的过程当中,总结出来的应用于不同场景的代码编写模版,那么今天我们就来学习一下一个最基础的设计模式——工厂模式。
工厂模式属于创建型的设计模式,顾名思义,所谓的工厂,就是专门用来生产的,那么在编程当中,工厂模式的工厂,就是专门为我们生产 “实例” 的。在平常的使用当中,比如A类当中的某个方法需要使用到B类,则需要A类在自己的方法当中对B类进行new出一个实例,之后再进行应用,而这时候C类如果也需要在自己的方法当中使用B类,则也需要在自己的方法当中对B类实例化,这时候如果将B类实例化这个工作交与D类去做,而A类和C类都直接从D类去获取B类的实例直接进行使用,那么这时候的D类,就是我们所说的工厂类。也许你会问,不就是一个new操作嘛,何必需要再弄一个D类来new,不是更麻烦吗?如果我们约定,对B类进行实例化后,需要对B类当中的100种变量进行重新赋值(这里只是打个比方,实际上不会有那么变态的场景,之所以这么说,是为了表述B的实例化变为了一个复杂的过程)才能对B类的实例进行使用呢?这时候如果不引用D类(工厂类)那么需要在A类当中的方法写101行代码,在C类当中的方法也写相同的101行代码,这就显得很复杂了,所以这时候我们的工厂类就登场了。
那么接下来我们先介绍工厂模式当中的最简单的形式——静态工厂模式(简单工厂模式)
1.简单工厂模式:在静态工厂模式当中有这么几个概念:
1)工厂类:即要生产产品(实例)的类;
2)抽象产品:它一般是具体产品继承的父类或者实现的接口。
3)具体产品:工厂类所创建的对象就是此角色的实例。在Java中由一个具体类实现。
首先我们来设定这么一个背景:想必大家对本田车(Honda车)有一点的了解,那么假定现在有两种型号的本田车,CRV和URV,用户可能会对这两种车进行使用。那么在这里例子当中呢,我们的工厂类就是本田车厂,抽象产品为Honda车,而具体产品为:CRV和URV,接下来我们看看代码。
public interface Honda { //抽象产品 public void CarVersion(); }
//具体产品 public class CRV implements Honda { @Override public void CarVersion() { System.out.println("this is CRV"); } } class URV implements Honda { @Override public void CarVersion() { System.out.println("this is URV"); } }
//工厂类 public class HondaFactory { public Honda createTheCar(String version) { switch (version) { case "CRV": return new CRV(); case "URV": return new URV(); default: break; } return null; } }
//客户类、 public class Customer { public static void main(String[] args) { HondaFactory f=new HondaFactory(); Honda crv=f.createTheCar("CRV"); crv.CarVersion(); Honda urv=f.createTheCar("URV"); urv.CarVersion(); } }
//运行结果 this is CRV this is URV
可以看到,客户根本不关心这两种车是怎么实现的,客户类所做的操作就是到工厂类提 “车”,这就是简单的工厂模式,那么这种简单的工厂模式会有一个很大的局限性,就是如果我们再加一种车型叫做XRV,那么我们就需要对工厂类进行改造,添加switch当中的case,这是很不方便的,为了解决这个问题,又提出了工厂方法模式。
2.工厂方法模式
工厂方法模式比起简单的工厂模式来说,不同点就在于它将工厂类也分为了抽象工厂和具体的工厂,抽象工厂呢,它是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 在这个例子当中,我们的抽象工厂就是Honda的造车厂,而具体的工厂,就分化出来了CRV的造车厂,URV的造车厂,用这样的方法,在添加一种车型叫XRV的话,我们只需要添加一个具体的XRV的造车厂就可以,而不需要修改其他任何已有的代码。接下来看具体的代码:
//抽象产品 public interface HondaCar { public void CarVersion(); }
//具体产品 public class CRV implements HondaCar { @Override public void CarVersion() { System.out.println("this is CRV"); } } class URV implements HondaCar { @Override public void CarVersion() { System.out.println("this is URV"); } } class XRV implements HondaCar { @Override public void CarVersion() { System.out.println("this is XRV"); } }
//抽象工厂 public interface HondaFactory { HondaCar buildTheCar(); }
//具体工厂 public class CRVFactory implements HondaFactory { @Override public HondaCar buildTheCar() { // TODO Auto-generated method stub return new CRV(); } } class URVFactory implements HondaFactory { @Override public HondaCar buildTheCar() { // TODO Auto-generated method stub return new URV(); } } class XRVFactory implements HondaFactory { @Override public HondaCar buildTheCar() { // TODO Auto-generated method stub return new XRV(); } }
//客户 public class Customer { public static void main(String[] args) { HondaFactory c=new CRVFactory(); HondaCar crv=c.buildTheCar(); crv.CarVersion(); HondaFactory u=new URVFactory(); HondaCar urv=u.buildTheCar(); urv.CarVersion(); HondaFactory x=new XRVFactory(); HondaCar xrv=x.buildTheCar(); xrv.CarVersion(); } }
//运行结果 this is CRV this is URV this is XRV
通过工厂方法模式,我们看似完美的解决了添加车型的问题,但是,如果由于车型的不同,导致车上的配件的档次也不相同,比如说:在URV上,我们需要装高级的空调和座椅,而CRV上我们可能就装中级的空调和座椅,那么这时候我们就需要采用抽象工厂的方法的形式来解决。这里我们来举个例子来说明抽象工厂和工厂方法的区别:
我们依然拿生产汽车的例子来说明他们之间的区别。
在上面的类图中,两厢车和三厢车称为两个不同的等级结构;而2.0排量车和2.4排量车则称为两个不同的产品族。再具体一点,2.0排量两厢车和2.4排量两厢车属于同一个等级结构,2.0排量三厢车和2.4排量三厢车属于另一个等级结构;而2.0排量两厢车和2.0排量三厢车属于同一个产品族,2.4排量两厢车和2.4排量三厢车属于另一个产品族。
明白了等级结构和产品族的概念,就理解工厂方法模式和抽象工厂模式的区别了,如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。在本例中,如果一个工厂模式提供2.0排量两厢车和2.4排量两厢车,那么他属于工厂方法模式;如果一个工厂模式是提供2.4排量两厢车和2.4排量三厢车两个产品,那么这个工厂模式就是抽象工厂模式,因为他提供的产品是分属两个不同的等级结构。当然,如果一个工厂提供全部四种车型的产品,因为产品分属两个等级结构,他当然也属于抽象工厂模式了。(参考:http://blog.csdn.net/zhengzhb/article/details/7359385/)
明白了之后我们再回到我们的本田车的例子当中,接下来我们来看看本田车的抽象工厂去实现CRV使用中级座椅和空调,而URV使用高级座椅和空调的代码:
//抽象产品接口 public interface HondaCar { public void CarVersion(); } public interface AirCondition { void AirconditionVersion(); } public interface Seat { void SeatLevel(); }
//具体产品类 class highAC implements AirCondition { @Override public void AirconditionVersion() { System.out.println("this is high AC"); } } class MiddleAC implements AirCondition { @Override public void AirconditionVersion() { System.out.println("this is middle AC"); } } class HighSeat implements Seat { @Override public void SeatLevel() { System.out.println("this is the High seat"); } } class MiddleSeat implements Seat { @Override public void SeatLevel() { System.out.println("this is the Middle seat"); } } class CRV implements HondaCar { @Override public void CarVersion() { System.out.println("this is CRV"); } } class URV implements HondaCar { @Override public void CarVersion() { System.out.println("this is URV"); } } class XRV implements HondaCar { @Override public void CarVersion() { System.out.println("this is XRV"); } }
//抽象工厂 public interface HondaFactory { HondaCar buildTheCar(); AirCondition getTheAirCondition(); Seat getTheSeat(); }
//具体工厂 public class CRVFactory implements HondaFactory { @Override public HondaCar buildTheCar() { // TODO Auto-generated method stub return new CRV(); } @Override public AirCondition getTheAirCondition() { // TODO Auto-generated method stub return new MiddleAC(); } @Override public Seat getTheSeat() { // TODO Auto-generated method stub return new MiddleSeat(); } } class URVFactory implements HondaFactory { @Override public HondaCar buildTheCar() { // TODO Auto-generated method stub return new URV(); } @Override public AirCondition getTheAirCondition() { // TODO Auto-generated method stub return new highAC(); } @Override public Seat getTheSeat() { // TODO Auto-generated method stub return new HighSeat(); } }
//客户 public class Customer { public static void main(String[] args) { HondaFactory c=new CRVFactory(); HondaCar crv=c.buildTheCar(); crv.CarVersion(); HondaFactory u=new URVFactory(); HondaCar urv=u.buildTheCar(); urv.CarVersion(); } }
到此,工厂模式就介绍完毕了。
总结一下:
简单工厂模式:对于增加新产品无能为力
工厂方法模式:通过新增实现具体工厂类的方式,可以增加新产品。
抽象工厂模式:对增加新产品无能为力,但是可以增加新产品族
本文参考了:http://blog.csdn.net/jason0539/article/details/23020989#comments 当中的博客,并且再加之自己的理解和话进行重新表述,也许引用的例子会大部分类似,还请谅解。