昨天写了单例模式了,今天是时候写工厂模式啦~
工厂模式我个人认为其实比较难理解的,如果有接触过|听过|见过该模式的同学很可能就会想:我自己new一个对象出来就好了,简单快捷。用得着你这个工厂模式吗?搞一个工厂出来还要写一大堆的代码呢~
网上的很多资料都是在阐述着:工厂模式的好处就是解耦。相信大家对解耦这个词也不陌生,那解耦究竟有什么好处呢?
在《设计模式之禅》这本书中分了两章节讲工厂模式:
网上的大部分资料都是将工厂模式分成三种:
看完上面的叙述是不是想打死我,什么鸟玩意?不急哈,下面我会一一讲到~~
想想我们为什么要用工厂模式?下面我就简单举例子:
文件IO的操作我们会经常用得到吧,所以BufferedReader对象经常要创建的:
//创建一个BufferedReader对象BufferedReaderbf=newBufferedReader(newFileReader(newFile("aa.txt")));你说麻烦吗?其实也不麻烦,就一行代码嘛,哪里麻烦了~如果不太熟悉IO流的同学就没有那么机灵了,创建一个BufferedReader可能就是以下的代码了:
Filefile=newFile("aa.txt");FileReaderfileReader=newFileReader(file);BufferedReaderbufferedReader=newBufferedReader(fileReader);你说麻烦吗?其实也不麻烦,不就是三行代码嘛,哪里麻烦了~如果这个应用很多的类上都用到了BufferedReader对象的话,那每个类都写上这三行代码了。那你说麻烦吗?那肯定麻烦啊,还用想啊....
可以看出来,创建一个BufferReader对象里面需要一个FileReader对象,而FileReader对象又要File对象。那创建这个BufferReader对象还是比较麻烦的(代码上看不麻烦,从构造上看还是挺麻烦的)!
虽然比较麻烦,但我们还能用,能用就行!于是乎,我们就去写代码了,现在有三个类都要进行文件的读写操作,于是他们就有这样的代码:
此时:上头说,我要换成LineNumberReader来读写,有这个需求!那我们作为一个写代码的,能怎么办?很绝望也需要去完成呀。
哎,写个代码屁事真多...那有没有一种方法能够让创建对象变得简单而且修改对象时能很方便呢?
再说从面向对象的角度来看:我一个操作文件的类还要我会创建BufferReader是不是有点过分了?(职责没有分工好)
何为工厂?将我们的产品都交由工厂来生产!我现在用的iphone5s,从哪来?从富士康组装而来,富士康是工厂。我用得着知道iphone5s在富士康是怎么组装起来的吗?不需要。
来,我们来改造一下上面的例子。首先我们创建一个工厂类,它可以生产Reader对象!
//创建Reader对象的工厂publicclassReaderFactory{publicstaticReadergetReader()throwsFileNotFoundException{Filefile=newFile("aa.txt");FileReaderfileReader=newFileReader(file);BufferedReaderreader=newBufferedReader(fileReader);returnreader;}}那么我们要得到BufferReader对象就贼简单了:
publicclassFileOperateA{publicstaticvoidmain(String[]args)throwsFileNotFoundException{//-------我有工厂了,还用自己搞吗?不用了!//Filefile=newFile("aa.txt");//FileReaderfileReader=newFileReader(file);//BufferedReaderbufferedReader=newBufferedReader(fileReader);//-------我有工厂了,还用自己搞吗?不用了! //用工厂来创建出对象Readerreader=ReaderFactory.getReader();//读写文件....}}工厂将我们创建的对象过程给屏蔽了!
此时我要改成LineNumberReader怎么玩?在工厂上改一下就好了:
我们的调用方FileOperateA|FileOperateB|FileOperateC这些类完全就不用变!
从上面的工厂模式体验我们就可以看到:
这就是解耦的好处!
我再放下我之前练习的时候写过的代码吧:
我有一个DaoFactory,逻辑很简单就是专门创建Dao对象的~
那么在Service层就可以使用工厂将想要的Dao对象初始化了~
此时我们的Service与Dao的对象低耦合的~
在Service与Controller层我也弄了一个ServiceFactory,根据当时业务的需要(添加权限),我创建Service时就非常灵活了:
在一开始我就说了,工厂模式可以分成三类:
下面我就逐一来介绍一下每一种工厂模式有什么不一样~
三种模式都以:Java3y要买宠物的例子来讲解~
很多博客都是以简单/静态工厂模式,工厂方法模式,抽象工厂模式这个顺序来讲解工厂模式的。我认为按书上的顺序比较好理解~因为简单/静态工厂模式是在工厂方法模式上缩减,抽象工厂模式是在工厂方法模式上再增强。
Java3y每天写代码很无聊,想要买只宠物来陪陪自己。于是乎就去宠物店看宠物啦~~~
作为一间宠物店,号称什么宠物都有!于是乎,店主宣传的时候就说:我的宠物店什么宠物都有!
于是构建宠物的工厂就诞生了~
猫工厂:
//继承着宠物工厂publicclassCatFactoryimplementsAnimalFactory{@Override//创建猫publicAnimalcreateAnimal(){returnnewCat();}}狗工厂也是一样的:
//继承着宠物工厂publicclassDogFactoryimplementsAnimalFactory{ //创建狗 @Override publicAnimalcreateAnimal(){ returnnewDog(); }}嗯,还有我们的实体类:猫、狗、动物(多态:猫和狗都是动物,可以直接用动物来表示了)
动物实体类:
publicabstractclassAnimal{ //所有的动物都会吃东西 publicabstractvoideat();}猫实体类:
publicclassCatextendsAnimal{ //猫喜欢吃鱼 @Override publicvoideat(){ System.out.println("猫吃鱼"); }}狗实体类:
publicclassDogextendsAnimal{ //狗喜欢吃肉 @Override publicvoideat(){ System.out.println("狗吃肉"); }}那么现在Java3y想要一只狗,跟了宠物店老板说,宠物店老板就去找狗回来了:
//要买蜥蜴..AnimalFactoryfff=newLizardFactory();Animalaaa=ff.createAnimal();aaa.eat();优点:
缺点:
工厂方法类图:
现在宠物店生意不好做啊,号称“什么宠物都有",这吹过头了~~于是店主只卖两种常见的宠物了。
所以我们的工厂是这样子的:
publicclassAnimalFactory{publicstaticDogcreateDog(){returnnewDog();}publicstaticCatcreateCat(){returnnewCat();}//外界想要猫要狗,这里创建就好了publicstaticAnimalcreateAnimal(Stringtype){if("dog".equals(type)){returnnewDog();}elseif("cat".equals(type)){returnnewCat();}else{returnnull;}}}三个实体还是没变(动物、猫、狗)....
那么Java3y去宠物店买猫狗的时候,告诉老板我要猫、我要狗:
//拿到狗AnimalA=AnimalFactory.createAnimal("dog");A.eat(); //拿到猫AnimalC=AnimalFactory.createAnimal("cat");C.eat();现在问题来了:
简单工厂类的优点也很明显:我就一个具体的工厂来创建对象,代码量少。
抽象工厂模式就比较复杂了,我们一般的应用都写不到。我首先来简述一下需求吧:
那我们的猫和狗都是有性别的,不是公的就是母的~~
具体的代码是这样的:
我们的最大工厂还是定义了创建什么动物
publicinterfaceAnimalFactory{ AnimalcreateDog(); AnimalcreateCat();}创建母猫和母狗的工厂:
publicclassFemaleAnimalFactoryimplementsAnimalFactory{//生产母狗和母猫@OverridepublicAnimalcreateDog(){returnnewFemaleDog();}@OverridepublicAnimalcreateCat(){returnnewFemaleCat();}}创建公猫和公狗的工厂:
publicclassMaleAnimalFactoryimplementsAnimalFactory{//生产公狗和公猫@OverridepublicAnimalcreateDog(){returnnewMaleDog();}@OverridepublicAnimalcreateCat(){returnnewMaleCat();}}这是所有动物都拥有的普遍行为:
publicabstractclassAnimal{ //所有的动物都会吃东西 publicabstractvoideat(); //所有的动物都有性别 publicabstractvoidgender();}这是猫都拥有的普遍行为:
publicabstractclassCatextendsAnimal{ //猫喜欢吃鱼 @Override publicvoideat(){ System.out.println("猫吃鱼"); }}这是狗都拥有的普遍行为:
publicabstractclassDogextendsAnimal{ //狗喜欢吃肉 @Override publicvoideat(){ System.out.println("狗吃肉"); }}猫分为公猫、母猫。狗分为公狗和母狗:
publicclassFemaleCatextendsCat{publicvoidgender(){System.out.println("IamafemaleCat");}}.....
简单来说:工厂方法模式的工厂是创建出一种产品,而抽象工厂是创建出一类产品。
这是抽象工厂模式的类图:
抽象工厂模式说到底就是多了一层抽象,减少了工厂的数量。