简单工厂和工厂方法模式
简单工厂:一个抽象产品类,派生出多个具体产品类;一个工厂类,每个工厂类可创建多个具体产品类的实例。“一对多”的关系。
工厂方法:一抽象产品类派生出多个具体产品类;一抽象工厂类派生出多个具体工厂类;每个具体工厂类只能创建一个具体产品类的实例。
即定义一个创建对象的接口(即抽象工厂类),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)。“一对一”的关系。
引用博客链接:http://blog.csdn.net/carterjin/article/details/8055220
四、简单工厂模式
简单工厂模式,顾名思义就是模式比较简单,实现起来比较具体的。
组成的三种角色分别为:
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();
- }
- }
我们今天心情高兴,告诉主管我们想要开大奔粗们~~~主管就会很听话的告诉奔驰的师傅来准备好奔驰车了。
工厂方法使用一个抽象工厂角色作为核心来代替在简单工厂模式中使用具体类作为核心。
让我们来看看工厂方法模式给我们带来了什么?使用开闭原则来分析下工厂方法模式。
当有新的产品(即我们的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的原则来生成,那么就可以被客户使用,而不必去修改任何已有的代码。看来,工厂方法模式是完全符合开闭原则的!
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。