只有光头才能变强html
回顾前面:设计模式
昨天写了单例模式了,今天是时候写工厂模式啦~微信
工厂模式我我的认为其实比较难理解的,若是有接触过|听过|见过该模式的同窗极可能就会想:我本身new
一个对象出来就行了,简单快捷。用得着你这个工厂模式吗?搞一个工厂出来还要写一大堆的代码呢~iphone
网上的不少资料都是在阐述着:工厂模式的好处就是解耦。相信你们对解耦这个词也不陌生,那解耦究竟有什么好处呢?ide
本文章试图去解释为何要用工厂模式,用了工厂模式的好处是什么,以及工厂模式衍生出的三种形式究竟有什么区别~~post
那么接下来就开始吧,若是有错的地方但愿能多多包涵,并不吝在评论区指正!spa
在《设计模式之禅》这本书中分了两章节讲工厂模式:.net
网上的大部分资料都是将工厂模式分红三种:设计
看完上面的叙述是否是想打死我,什么鸟玩意?不急哈,下面我会一一讲到~~3d
想一想咱们为何要用工厂模式?下面我就简单举例子:
文件IO的操做咱们会常常用获得吧,因此BufferedReader对象常常要建立的:
// 建立一个BufferedReader对象 BufferedReader bf = new BufferedReader(new FileReader(new File("aa.txt")));
你说麻烦吗?其实也不麻烦,就一行代码嘛,哪里麻烦了~若是不太熟悉IO流的同窗就没有那么机灵了,建立一个BufferedReader可能就是如下的代码了:
File file = new File("aa.txt"); FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader);
你说麻烦吗?其实也不麻烦,不就是三行代码嘛,哪里麻烦了~若是这个应用不少的类上都用到了BufferedReader对象的话,那每一个类都写上这三行代码了。那你说麻烦吗?那确定麻烦啊,还用想啊....
能够看出来,建立一个BufferReader对象里面须要一个FileReader对象,而FileReader对象又要File对象。那建立这个BufferReader对象仍是比较麻烦的(代码上看不麻烦,从构造上看仍是挺麻烦的)!
虽然比较麻烦,但咱们还能用,能用就行!因而乎,咱们就去写代码了,如今有三个类都要进行文件的读写操做,因而他们就有这样的代码:
public class FileOperateA { public static void main(String[] args) throws FileNotFoundException { File file = new File("aa.txt"); FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader); // 读写文件.... } }
此时:上头说,我要换成LineNumberReader来读写,有这个需求!那咱们做为一个写代码的,能怎么办?很绝望也须要去完成呀。
哎,写个代码屁事真多...那有没有一种方法可以让建立对象变得简单并且修改对象时能很方便呢?
再说从面向对象的角度来看:我一个操做文件的类还要我会建立BufferReader是否是有点过度了?(职责没有分工好)
何为工厂?将咱们的产品都交由工厂来生产!我如今用的iphone5s,从哪来?从富士康组装而来,富士康是工厂。我用得着知道iphone5s在富士康是怎么组装起来的吗?不须要。
来,咱们来改造一下上面的例子。首先咱们建立一个工厂类,它能够生产Reader对象!
// 建立Reader对象的工厂 public class ReaderFactory { public static Reader getReader() throws FileNotFoundException { File file = new File("aa.txt"); FileReader fileReader = new FileReader(file); BufferedReader reader = new BufferedReader(fileReader); return reader; } }
那么咱们要获得BufferReader对象就贼简单了:
public class FileOperateA { public static void main(String[] args) throws FileNotFoundException { //-------我有工厂了,还用本身搞吗?不用了! //File file = new File("aa.txt"); //FileReader fileReader = new FileReader(file); //BufferedReader bufferedReader = new BufferedReader(fileReader); //-------我有工厂了,还用本身搞吗?不用了! // 用工厂来建立出对象 Reader reader = ReaderFactory.getReader(); // 读写文件.... } }
工厂将咱们建立的对象过程给屏蔽了!
此时我要改为LineNumberReader怎么玩?在工厂上改一下就行了:
咱们的调用方FileOperateA|FileOperateB|FileOperateC
这些类彻底就不用变!
从上面的工厂模式体验咱们就能够看到:
new
的方式来建立对象的话,那么咱们就说:new
出来的这个对象和当前客户端(调用方)耦合了!
new
出来的对象!这就是解耦的好处!
我再放下我以前练习的时候写过的代码吧:
我有一个DaoFactory,逻辑很简单就是专门建立Dao对象的~
那么在Service层就能够使用工厂将想要的Dao对象初始化了~
此时咱们的Service与Dao的对象低耦合的~
在Service与Controller层我也弄了一个ServiceFactory,根据当时业务的须要(添加权限),我建立Service时就很是灵活了:
在一开始我就说了,工厂模式能够分红三类:
下面我就逐一来介绍一下每一种工厂模式有什么不同~
三种模式都以:Java3y要买宠物的例子来说解~
不少博客都是以简单/静态工厂模式,工厂方法模式,抽象工厂模式这个顺序来说解工厂模式的。我认为按书上的顺序比较好理解~由于简单/静态工厂模式是在工厂方法模式上缩减,抽象工厂模式是在工厂方法模式上再加强。
Java3y天天写代码很无聊,想要买只宠物来陪陪本身。因而乎就去宠物店看宠物啦~~~
做为一间宠物店,号称什么宠物都有!因而乎,店主宣传的时候就说:个人宠物店什么宠物都有!
因而构建宠物的工厂就诞生了~
// 号称什么宠物都有 public interface AnimalFactory { // 能够获取任何的宠物 Animal createAnimal(); }
固然了,主流的宠物得进货一些先放在店里充充门面,一些特殊的宠物就告诉顾客要时间进货~
猫工厂:
// 继承着宠物工厂 public class CatFactory implements AnimalFactory { @Override // 建立猫 public Animal createAnimal() { return new Cat(); } }
狗工厂也是同样的:
// 继承着宠物工厂 public class DogFactory implements AnimalFactory { // 建立狗 @Override public Animal createAnimal() { return new Dog(); } }
嗯,还有咱们的实体类:猫、狗、动物(多态:猫和狗都是动物,能够直接用动物来表示了)
动物实体类:
public abstract class Animal { // 全部的动物都会吃东西 public abstract void eat(); }
猫实体类:
public class Cat extends Animal { // 猫喜欢吃鱼 @Override public void eat() { System.out.println("猫吃鱼"); } }
狗实体类:
public class Dog extends Animal { // 狗喜欢吃肉 @Override public void eat() { System.out.println("狗吃肉"); } }
那么如今Java3y想要一只狗,跟了宠物店老板说,宠物店老板就去找狗回来了:
// 去找狗工厂拿一只狗过来 AnimalFactory f = new DogFactory(); // 店主就拿到了一只狗给Java3y Animal a = f.createAnimal(); a.eat(); System.out.println("关注公众号:Java3y");
那么如今Java3y想要一只猫,跟了宠物店老板说,宠物店老板就去找猫回来了:
// 去找猫工厂拿一只猫过来 AnimalFactory ff = new CatFactory(); // 店主就拿到了一只猫给Java3y Animal aa = ff.createAnimal(); aa.eat(); System.out.println("关注公众号:Java3y");
若是这个时候Java3y说想要一只蜥蜴怎么办啊?没问题啊,店主搞个蜥蜴工厂就行了~~
// 要买蜥蜴.. AnimalFactory fff = new LizardFactory(); Animal aaa = ff.createAnimal(); aaa.eat();
优势:
缺点:
工厂方法类图:
如今宠物店生意很差作啊,号称“什么宠物都有",这吹过头了~~因而店主只卖两种常见的宠物了。
因此咱们的工厂是这样子的:
public class AnimalFactory { public static Dog createDog() { return new Dog(); } public static Cat createCat() { return new Cat(); } // 外界想要猫要狗,这里建立就行了 public static Animal createAnimal(String type) { if ("dog".equals(type)) { return new Dog(); } else if ("cat".equals(type)) { return new Cat(); } else { return null; } } }
三个实体仍是没变(动物、猫、狗)....
那么Java3y去宠物店买猫狗的时候,告诉老板我要猫、我要狗:
// 拿到狗 Animal A = AnimalFactory.createAnimal("dog"); A.eat(); // 拿到猫 Animal C = AnimalFactory.createAnimal("cat"); C.eat();
如今问题来了:
简单工厂类的优势也很明显:我就一个具体的工厂来建立对象,代码量少。
抽象工厂模式就比较复杂了,咱们通常的应用都写不到。我首先来简述一下需求吧:
那咱们的猫和狗都是有性别的,不是公的就是母的~~
具体的代码是这样的:
咱们的最大工厂仍是定义了建立什么动物
public interface AnimalFactory { Animal createDog(); Animal createCat(); }
建立母猫和母狗的工厂:
public class FemaleAnimalFactory implements AnimalFactory { // 生产母狗和母猫 @Override public Animal createDog() { return new FemaleDog(); } @Override public Animal createCat() { return new FemaleCat(); } }
建立公猫和公狗的工厂:
public class MaleAnimalFactory implements AnimalFactory { // 生产公狗和公猫 @Override public Animal createDog() { return new MaleDog(); } @Override public Animal createCat() { return new MaleCat(); } }
这是全部动物都拥有的广泛行为:
public abstract class Animal { // 全部的动物都会吃东西 public abstract void eat(); // 全部的动物都有性别 public abstract void gender(); }
这是猫都拥有的广泛行为:
public abstract class Cat extends Animal { // 猫喜欢吃鱼 @Override public void eat() { System.out.println("猫吃鱼"); } }
这是狗都拥有的广泛行为:
public abstract class Dog extends Animal { // 狗喜欢吃肉 @Override public void eat() { System.out.println("狗吃肉"); } }
猫分为公猫、母猫。狗分为公狗和母狗:
public class FemaleCat extends Cat { public void gender() { System.out.println("I am a female Cat"); } }
.....
简单来讲:工厂方法模式的工厂是建立出一种产品,而抽象工厂是建立出一类产品。
Animal createDog();
和Animal createCat();
public abstract void eat();
和public abstract void gender();
eat()
方法
gender()
方法eat()
方法
gender()
方法createDog()
和createCat()
生产母狗和母猫createDog()
和createCat()
生产公狗和共猫
public static void main(String[] args) { // 须要性别为母的就去找母工厂 AnimalFactory af = new FemaleAnimalFactory(); // 须要一只母猫 af.createCat().gender(); // 须要一只母狗 af.createDog().gender(); System.out.println("-------------关注公众号:Java3y-------------------------"); // 须要性别为公的就去找公工厂 AnimalFactory aff = new MaleAnimalFactory(); // 须要一只公狗 aff.createDog().gender(); // 须要一只公猫 aff.createCat().gender(); }
效果:
这是抽象工厂模式的类图:
抽象工厂模式说到底就是多了一层抽象,减小了工厂的数量。
抽象工厂缺点也很明显:
总的来讲咱们用简单工厂模式比较多,工厂方式模式的话代码量会比较大,抽象工厂模式的话须要业务比较大的状况下才会用到(若是有更好的理解方式不妨在评论区留言,一块儿交流交流涨涨见识~~)
参考资料:
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y。为了你们方便,刚新建了一下qq群:742919422,你们也能够去交流交流。谢谢支持了!但愿能多介绍给其余有须要的朋友
文章的目录导航: