最近学习了工厂模式,看了网上的教程,也学习了别人的代码,最后自己按照自己的想法实现了一下。
有想看原文的去这个网址 http://blog.csdn.net/mmquit/article/details/1672694
如果想要看我自己实现的源码的,去这个网址下载。支持下小弟工作和学习热情,辛苦整理实现的,收取1分哈~~~大家别拍砖~~~。顺带说一下怎么能快速的获取积分来下载,你可以经常上传你自己觉得很经典的书籍、文档、代码,乃至你自己写的一些小Demo,并设置一定的积分(别太高了,否则没人会怎么下,1-2分最好了),只要你的东西够好,就会有人下载学习的。人人奉献嘛~~~
好吧,有点扯远了。下面来看我自己理解的工厂模式。
温馨提示:请大家仔细分析和理解下文中前两种模式实现后的分析段落,原文作者真的写的很好。在这里表示敬意。
一、引子
话说在C语言这种面向过程的语言中,如果实现一个人去开车,是需要按照过程来一步一步的完成的,例如想开奔驰了,就会说“开奔驰车”,想开宝马了,就说“开宝马车”,想开奥迪了,就说“开奥迪车”。有没有觉得很麻烦?想到开什么车了,就必须要把车名也都带上,或者需要自己去生成一个车的对象来开。那么可不可以在Java语言中,充分的体现面向对象的特征呢?当然可以了,就是增加一个辅助的人来帮你,比如是一个司机。由他来具体负责今天开什么车,处理内部的逻辑,而你呢?只需要简简单单的说一句,“D~~r~~~ive!”。
喏,工厂模式出现了~~~你就好比一个客户端,司机就好比一个工厂,业务逻辑有它来处理。
二、工厂模式的分类
工厂模式按照范围或者抽象程度来说,可以大致分为三类:
1、简单工厂模式(Simple Factory)。这是最简单、最具体的一种,也是大多小型程序完全可以应付的一种。
2、工厂方法模式(Factory Method)。把简单工厂模式更加抽象化了,适合更加复杂、OO要求更高的程序或设计。
3、抽象工厂模式(Abstract Factory)。最抽象,但最具一般性的一种。
三、使用工厂模式的情景和前提
那么工厂模式这么好,我们需要在什么情况下使用呢?大致有两种:
1.在编码时不能预见需要创建哪种类的实例。
2.系统不应依赖于产品类实例(例如本文的车)如何被创建、组合和表达的细节。
**********************************************我是华丽的分割线*************************************************************************************************
好,下面开始正式的,讲三种工厂模式的前两种。
四、简单工厂模式
简单工厂模式,顾名思义就是模式比较简单,实现起来比较具体的。
组成的三种角色分别为:
1、工厂类角色 :这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。例如你雇的司机,由他来处理你想开车的逻辑。
2、抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。例如车这个模型,它是所有你想开的车的父类或接口。
3、具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。例如具体的某辆车,奔驰?宝马?奥迪?
具体的类图请看下面:
好,来简单实现以下吧
来定义一个抽象产品角色:Car
/**
* 作为抽象产品类,即它只代表是某种产品,具体的细节由具体的产品来实现。
*
*/
public interface Car {
/**
* 子类需要实现的方法,具体如何开动
*/
public abstract void drive();
}
再来定义具体产品角色:Benz、BMW、Audi
/**
* 奔驰车,继承与Car,实现了具体的开车细节
*/
public class Benz implements Car{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("奔驰车启动,嗡~~~~");
}
}
/**
* 宝马车,继承与Car,实现了具体的开车细节
*/
public class BMW implements Car{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("宝马车启动,嗡~~~~");
}
}
/**
* 奥迪车,继承于Car,实现了具体的开车细节。
*/
public class Audi implements Car{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("奥迪车启动,嗡~~~~");
}
}
这三个就是具体产品角色,是真正存在的车 。
下面,来最重要的工厂角色了,Driver。
/**
* 工厂类,由它来具体实现一些逻辑和业务上的细节
*
*/
public class Driver {
/**
* 启动一辆车,通过具体传入的车名,来生成并返回该车。
*
* @param carName 需要开的车名。Benz,BMW,Audi
* @return car 具体生成的车。注意多态。
* @throws Exception 没有找到传入的车名时报出异常。
*/
public static Car launch(String carName) throws Exception{
if( "Benz".equals(carName)){
return new Benz();
}else if("BMW".equals(carName)){
return new BMW();
}else if("Audi".equals(carName)){
return new Audi();
}else{
throw new Exception("没有该车型:" + carName );
}
}
}
Driver类就是工厂类,它负责具体的业务逻辑。例如你想开什么车,就传入车名,由他来处理这个名字,并为你提供这辆车。如果没有,则会告诉你一些错误。
该类有一个方法launch(),就是有它来处理业务细节的。具体怎么实现,还要看具体的需求,这里只是举例。
最后,该我们上场了,Supremo!!
public class Supremo {
public static void main(String[] args){
try {
Car car = Driver.launch("Benz");
car.drive();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
看到了吗?我们只是告诉司机我们想要开的车,司机就会自己进行处理并返回给我们,然后我们调用drive方法,就有具体的某辆车去执行开车方法了。
这便是简单工厂模式了。怎么样,很简单吧?那么它带来了什么好处呢?
首先,使用了简单工厂模式后,我们的程序不在“有病”,更加符合现实中的情况;
其次,客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品(正如我们的行为)。
下面我们从开闭原则上来分析下简单工厂模式。
当我们增加了一辆车的时候,只要符合抽象产品制定的原则,那么只要通知工厂类知道就可以被客户使用了。
那么对于产品部分来说,它是符合开闭原则的——对扩展开放、对修改关闭;
缺点:
但是工厂部分好像不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判断逻辑,这显自然是违背开闭原则的。
对于这样的工厂类(在我们的例子中是为司机师傅),我们称它为全能类或者上帝类。我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了,进而累坏了我们可爱的程序员:(
正如我前面提到的简单工厂模式适用于业务将简单的情况下。而对于复杂的业务环境可能不太适应阿。这就应该由工厂方法模式来出场了!!
五、工厂方法模式
上一种方法虽然很体现工厂设计模式,但过于简单,所有的逻辑都在一个类里实现,或多或少有点坑人的感觉啊,岂不是要累死人?万恶的资本主义了???
我们人类太聪明了,发现问题了怎么办?马上改进现有的机制呗。
在这种情况之下衍生了工厂方法模式,产品们还是依旧的产品们,但工厂?可不是曾经的那个工厂啦。“产房传喜讯,人家生(升)啦”。
怎么个意思?记得曾经的那个Driver类么?现在,它已经变成了一个司机部门的主管,由具体的实现类,变成了一个父类(接口)。但只有一个光杆司令是不行滴,所以要招聘员工了,王师傅(奔驰司机)、李师傅(宝马司机)、张师傅(奔驰司机)都来应聘成功!!!
来看看工厂方法模式的组成角色,比简单工厂多了一个角色:
1、抽象工厂类角色:工厂的抽象,是一般工厂的父类或实现的接口。在Java中由一个接口或抽象类来实现。例如我们程序的司机部门主管。
2、工厂类角色 :这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。例如你雇的司机,由他来处理你想开车的逻辑。
3、抽象产品角色 :它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。例如车这个模型,它是所有你想开的车的父类或接口。
4、具体产品角色 :工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。例如具体的某辆车,奔驰?宝马?奥迪?
具体的类图如下:
来看看实现吧~~~在简单工厂的基础之上,所有的产品都是不用动滴~~~需要改变的只是工厂类部门。
改动后的Driver
/**
* 工厂的接口,由它来定义一些需要完成的业务和逻辑,由具体的工厂去实现。例如司机部门主管。
*
*/
public interface Driver {
public abstract Car launchCar();
}
来看看司机们吧~~~王师傅、李师傅、张师傅登场~~~
/**
* 奔驰司机,继承于Driver,是一个具体的工厂类。
*/
public class BenzDriver implements Driver{
@Override
public Car launchCar() {
// TODO Auto-generated method stub
return new Benz();
}
}
/**
* 宝马司机,继承于Driver,是一个具体的工厂类。
*/
public class BMWDriver implements Driver{
@Override
public Car launchCar() {
// TODO Auto-generated method stub
return new BMW();
}
}
/**
* 奥迪司机,继承于Driver,是一个具体的工厂类。
*/
public class AudiDriver implements Driver{
@Override
public Car launchCar() {
// TODO Auto-generated method stub
return new Audi();
}
}
三个司机都归Driver类管,具体开什么车,他们自己会去负责。
当然我们的行为也是需要改的,我们只要去告诉主管去开哪个车就好了
public class Supremo {
public static void main(String[] args){
// 告诉主管我们需要一个奔驰车。
Driver driver = new BenzDriver();
Car car = driver.launchCar();
car.drive();
}
}
我们今天心情高兴,告诉主管我们想要开大奔粗们~~~主管就会很听话的告诉奔驰的师傅来准备好奔驰车了。
工厂方法使用一个抽象工厂角色作为核心来代替在简单工厂模式中使用具体类作为核心。
让我们来看看工厂方法模式给我们带来了什么?使用开闭原则来分析下工厂方法模式。
当有新的产品(即我们的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的原则来生成,那么就可以被客户使用,而不必去修改任何已有的代码。看来,工厂方法模式是完全符合开闭原则的!
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。
抽象工厂模式我还木有看懂,希望大家先看上面的,后面的我再理解理解,有需要的可以看本文开头的部分,有原帖地址。