JAVA 工厂模式

JAVA 工厂模式

 

使用场景

在具体介绍工厂模式之前,首先应该先对其使用场景有个了解,网上的例子虽然介绍了工厂模式的概念,但是看完之后,并没有感觉好在哪里,反而有点绕圈子的感觉。

 

场景1:比如类A,用到的地方很多,每个地方都需要new一个实例。如果此时对A做了修改(比如修改了构造函数的参数类型,或者需求变更,需要将A修改为A的子类),就需要修改所有引用的地方,这时将创建实例的过程放入工厂类中,如果类A有任何修改,只需修改工厂即可。

 

场景2:降低代码重复。如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的创建过程的修改维护。(当然,也可以把这些创建过程的代码放到类的构造函数里,同样可以降低重复率,而且构造函数本身的作用也是初始化对象。不过,这样也会导致构造函数过于复杂,做的事太多,不符合java 的设计原则。)

 

场景3:如果一个抽象类有很多子类,比如抽象类为UserDAO,子类为JDBCUserDAO和HibernateUserDAO,不同的情况下要调用不同子类,调用灵活,如果不使用工厂模式,则需要在业务逻辑中的类中,分别创建实例UserDAO udao = new JDBCUserDAO,UserDAO udao = new HibernateUserDAO,当需要更改需求,调用其他子类时,则需要修改业务逻辑的类,这样不符合一般的设计原则,通过工厂模式创建,则将创建和引用解耦,只需要修改创建部分就可以

 

以下大部分内容转自博客:http://blog.csdn.net/jason0539,对部分内容做了修改

引言

1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
2)简单工厂模式:后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
3)工厂方法模式时代:为了满足客户,宝马车系列越来越多,如320i523i,30li等系列一个工厂无法创建所有的宝马系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。

4)抽象工厂模式时代:随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车这就是工厂模式

分类 
        工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。 这里就不用产品族和等级结构等概念来说了,用不熟悉的词汇,来解释不熟悉的概念,反而将简单的东西,给搞复杂了。
工厂模式可以分为三类: 

1)简单工厂模式(Simple Factory 
2
)工厂方法模式(Factory Method 
3
)抽象工厂模式(Abstract Factory 

 这三种模式从上到下逐步抽象,并且更具一般性。 
        GOF
在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。

        将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。 

 

 

区别 
1 工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。

一个抽象工厂类,可以派生出多个具体工厂类。

每个具体工厂类只能创建一个具体产品类的实例。
2 抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类可以创建多个具体产品类的实例。   
3 区别:

工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
 

 

 简单工厂模式 


建立一个工厂(一个函数或一个类方法)来制造新的对象。
分布说明引子:从无到有。客户自己创建宝马车,然后拿来用。

下例为不实用工厂模式:

     BMW320(){  

        System.out.println() }  

     BMW523(){  

        System.out.println() }  

  Customer {  

       main(String[] args) {  

        BMW320 bmw320 =  BMW320();  

       BMW523 bmw523 =  BMW523();  

   }  

}

 

客户需要知道怎么去创建一款车,客户和车就紧密耦合在一起了.为了降低耦合,就出现了工厂类,把创建宝马的操作细节都放到了工厂里面去,客户直接使用工厂的创建工厂方法,传入想要的宝马车型号就行了,而不必去知道创建的细节.这就是工业革命了:简单工厂模式

即我们建立一个工厂类方法来制造新的对象。如图:

产品类:

abstract BMW {  

     BMW(){  

    }  

}  

  BMW320 extends  BMW {  

     BMW320() {  

        System.out.println() }  

  BMW523 extends   BMW{  

     BMW523(){  

        System.out.println( )   }  

}  

工厂类(伪代码)

public Factory {  

     BMW createBMW( type) {  

         (type) {  

             Type=320  new BMW320();  

              Type=523  new BMW523();  

        }  

    }  

}  


客户类:

public Customer {  

       main(String[] args) {  

        Factory factory =  Factory();  

        BMW bmw320 = factory.createBMW(320);  

        BMW bmw523 = factory.createBMW(523);  

    }  

}  

      简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。 
      
先来看看它的组成: 
           1)
工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
              2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。         
             3)
具体产品角色:工厂类所创建的对象就是此角色的实例。在Java中由一个具体类实现。 

 

         下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。当客户不再满足现有的车型号的时候,想要一种速度快的新型车,只要这种车符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的;但是工厂部分好像不太理想,因为每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑(createBMW(int type)方法需要新增case),这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。 
        我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。
        于是工厂方法模式作为救世主出现了。 工厂类定义成了接口,每新增的车种类型,就增加该车种类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码

 

工厂方法模式 


        工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。 
工厂方法模式组成: 
       1)
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 
       2)
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。 
       3)
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 
       4)
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 
       
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的上帝类。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有 的代码。可以看出工厂角色的结构也是符合开闭原则的! 

代码如下: 

产品类:

abstract BMW {  

     BMW(){  

    }  

}  

  BMW320 extends  BMW {  

     BMW320() {  

        System.out.println(    }  

}  

  BMW523 extends   BMW{  

     BMW523(){  

        System.out.println( }  

}
创建工厂类:

Interface FactoryBMW }  

  

  FactoryBMW320 implements  FactoryBMW{  

  

      

     BMW320 createBMW() {  

  

          New BMW320();  

    }  

  

}  

  FactoryBMW523 implements  FactoryBMW {  

     BMW523 createBMW() {  

          New BMW523();  

   }  

}  


客户类:

public Customer {  

       main(String[] args) {  

        FactoryBMW320 factoryBMW320 =  FactoryBMW320();  

        BMW320 bmw320 = factoryBMW320.createBMW();  

        FactoryBMW523 factoryBMW523 =  FactoryBMW523();  

        BMW523 bmw523 = factoryBMW523.createBMW();  

    }  

}  


       工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口,但使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。

以上就是简单工厂模式,工厂方法模式

 

抽象工厂模式

 

例子背景:

随着客户的要求越来越高,宝马车需要不同配置的空调和发动机等配件。于是这个工厂开始生产空调和发动机,用来组装汽车。这时候工厂有两个系列的产品:空调和发动机。宝马320系列配置A型号空调和A型号发动机,宝马523系列配置B型号空调和B型号发动机。

 

概念:

      抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如宝马320系列使用空调型号A和发动机型号A,而宝马523系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A

 

当每个抽象产品都有多于一个的具体子类的时候(空调有型号AB两种,发动机也有型号AB两种),工厂角色怎么知道实例化哪一个子类呢?

比如每个抽象产品角色都有两个具体产品(产品空调有两个具体产品空调A和空调B)。

抽象工厂模式提供两个具体工厂角色(宝马320系列工厂和宝马523系列工厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

 

抽象工厂模式代码

 

 产品类: 

//发动机以及型号   

public Engine {    

}    

  EngineA  extends  Engine{    

     EngineA(){    

        System.out.println() }    

}

  EngineB extends Engine{    

     EngineB(){    

        System.out.println()    }    

}    

 

  Aircondition {    

}    

  AirconditionA extends   Aircondition{    

     AirconditionA(){    

        System.out.println()    }    

}    

  AirconditionB extends    Aircondition{    

     AirconditionB(){    

        System.out.println() }   

}


创建工厂类:

//创建工厂的接口   

public AbstractFactory {    

     Engine createEngine();  

     Aircondition createAircondition();   

}    

  FactoryBMW320 extends  AbstractFactory{    

     Engine createEngine() {      

          EngineA();    

    }    

     Aircondition createAircondition() {    

          AirconditionA();    

    }    

}    

  

  FactoryBMW523 extends  AbstractFactory {    

     Engine createEngine() {      

          EngineB();    

    }    

        

     Aircondition createAircondition() {    

          AirconditionB();    

    }    

}   

 

客户:

public Customer {    

       main(String[] args){    

        FactoryBMW320 factoryBMW320 =  FactoryBMW320();    

        factoryBMW320.createEngine();  

        factoryBMW320.createAircondition();  

        FactoryBMW523 factoryBMW523 =  FactoryBMW523();    

        factoryBMW320.createEngine();  

        factoryBMW320.createAircondition();  

    }    

}  

 

 

整理一波

 

 

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

       所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值