转载请注明出处!!!http://blog.csdn.net/zhonghuan1992
全部配套代码均在github上:https://github.com/ZHONGHuanGit/DesignPattern
跟着ZHONGHuan学习设计模式
工厂方法
简单介绍:
上一篇我们介绍了简单工厂,还记得简单工厂的缺点么?忘了回去浏览一下(这里)!由于简单工厂创造了一个万能的上帝工厂类,它把全部的工作都包了。当我们添加一个新的产品的时候,我们仍须要改动工厂中的方法。而工厂方法改进了简单工厂这一缺点,而且保留了原有的长处。怎么做到的,继续看下去!
在工厂方法中,核心的工厂类摇身一变,变为一个抽象的工厂角色,而将详细的工作交给详细的子类去做。这个就是工厂方法对简单工厂的改进。言语表达不清,请看以下的类图。
UML类图:
还是类图比較直观。从类图中,我们看到,原来简单工厂的核心工厂类,变为了抽象工厂和继承它的详细工厂。产品如今都是由详细工厂来生产。每一个详细工厂比較专心,生产一个产品,(当然,假设有必要,你能够让一个详细工厂生产多个产品)。实现请看以下的代码。
工厂方法的代码实现:
interface AbstractProduct { } //详细产品1 class Product1 implements AbstractProduct { public Product1(){ System.out.println("生产详细产品1"); } } //详细产品2 class Product2 implements AbstractProduct{ public Product2(){ System.out.println("生产详细产品2"); } } //抽象工厂,详细的实现交给实现该接口的详细工厂类去完毕, interface AbstractFactory { public AbstractProduct create(); } //详细工厂类1,主要生产详细产品1 class Factory1 implements AbstractFactory { public AbstractProduct create() { return new Product1(); } } //详细工厂类2,主要生产详细产品2 class Factory2 implements AbstractFactory { public AbstractProduct create() { return new Product2(); } } public class Main { public static void main(String[] args) { AbstractFactory factory = new Factory1(); Product1 prodect1 = (Product1)factory.create();//生产了详细产品1 factory = new Factory2(); Product2 prodect2 = (Product2)factory.create();//生产了详细产品2 } }
结构与角色:
抽象工厂(AbstractFactory)角色:担任这个角色的是工厂方法模式的核心,它是与应用程序无关的。不论什么在模式中创建对象的工厂类必须实现这个接口。在上面的系统中这个角色由接口Creator 扮演;在实际的系统中,这个角色也常用抽象类实现。
详细工厂(ConcreteFactory)角色:担任这个角色的是实现了抽象工厂接口的详细类。详细工厂角色含有与应用密切相关的逻辑,而且受到应用程序的调用以创建产品对象。
在上面的样例中给出了两个这种角色,也就是详细Java 类Factory1 和Factory2。
工厂方法模式的长处:
n 在工厂方法模式中,核心的工厂类不再负责全部的产品的创建,而是将详细创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出详细工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这样的细节
n 这样的进一步抽象化的结果,使这样的工厂方法模式能够用来同意系统在不改动详细工厂角色的情况下引进新的产品
为什么要用工厂模式?
在上面一篇简单工厂中,没有体现出工厂模式的优点,所以在这里补充一下。
我们泡面来举例,而且正好这篇是工厂方法,所以,这里顺便体现一下工厂方法的优势。首先方便面有非常多种类,有海鲜的,红烧的(我比較喜欢经典的红烧)等等。所以抽象一个方便面类InstantNoodle。
如果不考虑工厂,我们肚子饿了,要泡面,直接就泡了是不是。在代码中可能是以下这样:
interface InstantNoodle{ void addOil();//意思是加油 void addPeiLiao();//意思是加配料,原谅我用汉字拼音表示 } class HaiXian implements InstantNoodle{//意思是海鲜面 public HaiXian(){ System.out.println("拆了一包海鲜面"); } public void addOil(){ System.out.println("加了点油"); } public void addPeiLiao(){ System.out.println("加了点海鲜风味的配料"); } } class HongShao implements InstantNoodle{//意思是红烧面 public HongShao(){ System.out.println("拆了一包红烧面"); } public void addOil(){ System.out.println("加了点油,红烧面的油味道比較重哦!"); } public void addPeiLiao(){ System.out.println("经典的红烧面配料"); } } public class Main{ public static void main(String[] args){ //如果如今肚子饿了,開始做面 System.out.println("我要開始做红烧面了"); InstantNoodle noodle1=new HongShao(); noodle1.addOil(); noodle1.addPeiLiao(); System.out.println("面做完了"); System.out.println("-----------------------------------------------"); //另外一个人想要吃海鲜面 System.out.println("我要開始做海鲜面了"); InstantNoodle noodle2=new HaiXian(); noodle2.addOil(); noodle2.addPeiLiao(); System.out.println("面做完了"); System.out.println("-----------------------------------------------"); } }
非常麻烦是不是,每次做面,都要自己写一堆代码,这些事情包含加油啦,放配料啦,事实上泡面只是就是一些流程,封装起来就好了,每次要吃面,直接告诉工厂,返回来给我就好了。所以简单工厂的实现是以下这种。
interface InstantNoodle{ void addOil();//意思是加油 void addPeiLiao();//意思是加配料,原谅我用汉字拼音表示 } class HaiXian implements InstantNoodle{//意思是海鲜面 public HaiXian(){ System.out.println("拆了一包海鲜面"); } public void addOil(){ System.out.println("加了点油"); } public void addPeiLiao(){ System.out.println("加了点海鲜风味的配料"); } } class HongShao implements InstantNoodle{//意思是红烧面 public HongShao(){ System.out.println("拆了一包红烧面"); } public void addOil(){ System.out.println("加了点油,红烧面的油味道比較重哦!"); } public void addPeiLiao(){ System.out.println("经典的红烧面配料"); } } class Factory{ public InstantNoodle create(String str){ InstantNoodle noodle=null; if(str.equals("HaiXian")){ System.out.println("我要開始做红烧面了"); noodle=new HongShao(); noodle.addOil(); noodle.addPeiLiao(); System.out.println("面做完了"); } if(str.equals("HongShao")){ System.out.println("我要開始做海鲜面了"); noodle=new HaiXian(); noodle.addOil(); noodle.addPeiLiao(); System.out.println("面做完了"); } System.out.println("-----------------------------------------------"); return noodle; } } public class Main{ public static void main(String[] args){ Factory fac=new Factory(); //如果如今肚子饿了,開始做面,第一个人想吃海鲜面 InstantNoodle noodle1=fac.create("HaiXian"); //另外一个人想要吃海鲜面 InstantNoodle noodle2=fac.create("HongShao"); } }
但是即使这样,也有不尽如人意的地方,方便面有非常多种做法,每一个人的做法不尽同样,当然上面就仅仅有几个因素。比方一个人喜欢先加油,再配料;另外一个人喜欢先配料,再加油。你可能会认为不就是泡面嘛,讲究这么多干嘛。但是,严格的说,这些先后顺序是会影响我们的面的口感的。假设仅仅是上面的两种先后顺序,可能你会说,简单工厂能够搞定,但是假设因素比較多了,而且我们无法事先把全部因素都放进简单工厂内,那么后面来了新的要求,我们就没有办法,须要更改简单工厂的代码了,这就违反了开闭原则。所以,使用工厂方法来解决问题。工厂方法的解决方式是以下这样。
interface InstantNoodle { void addOil();// 意思是加油 void addPeiLiao();// 意思是加配料,原谅我用汉字拼音表示 } class HaiXian implements InstantNoodle {// 意思是海鲜面 public HaiXian() { System.out.println("拆了一包海鲜面"); } public void addOil() { System.out.println("加了点油"); } public void addPeiLiao() { System.out.println("加了点海鲜风味的配料"); } } class HongShao implements InstantNoodle {// 意思是红烧面 public HongShao() { System.out.println("拆了一包红烧面"); } public void addOil() { System.out.println("加了点油,红烧面的油味道比較重哦!"); } public void addPeiLiao() { System.out.println("经典的红烧面配料"); } } interface Factory { InstantNoodle create(); } // 海鲜面制作工厂,使用先加油,后放配料做法 class HaiXianFac1 implements Factory { public InstantNoodle create() { System.out.println("我要開始做海鲜面了,制作手法为先加油,后放配料"); InstantNoodle noodle = new HaiXian(); noodle.addOil(); // 这里是先加油,后放配料 noodle.addPeiLiao(); System.out.println("-----------------------------------------------"); return noodle; } } // 海鲜面制作工厂,使用先放配料,后加油做法 class HaiXianFac2 implements Factory { public InstantNoodle create() { System.out.println("我要開始做海鲜面了,使用制作手法为先放配料,后加油"); InstantNoodle noodle = new HaiXian(); noodle.addPeiLiao(); noodle.addOil(); // 这里是先放配料,后加油 System.out.println("-----------------------------------------------"); return noodle; } } public class Main { public static void main(String[] args) { // 如果如今肚子饿了,開始做面,第一个人想吃海鲜面,他喜欢先加油,后放配料 Factory fac1 = new HaiXianFac1(); InstantNoodle noodle1 = fac1.create(); // 另外一个人也想要吃海鲜面,他喜欢先方配料,后加油 Factory fac2 = new HaiXianFac2(); InstantNoodle noodle2 = fac2.create(); } }
增加另一些人对红烧面有一些要求,新建工厂类,来生产符合这个要求的产品,这种做法更加符合开闭原则。通过使用工厂方法,可以解决上述的问题。当然或许会有更好的解决方式,我说上述的样例,仅仅是为了可以表示工厂模式的优势。