zoukankan      html  css  js  c++  java
  • Java工厂模式

    Java工厂模式

    看了这么多关于工厂模式的解说,还是认为这篇文章讲的好理解,贴出来和大家分享分享。
    一、引子
                话说十年前,有一个****户,他家有三辆汽车——Benz奔驰、Bmw宝马、Audi奥迪,还雇了司机为他开车。只是,****户坐车时总是怪怪的:上Benz车后跟司机说“开奔驰车!”,坐上Bmw后他说“开宝马车!”,坐上Audi说“开奥迪车!”。你一定说:这人有病!直接说开车不即可了?!
                 而当把这个****户的行为放到我们程序设计中来时,会发现这是一个普遍存在的现象。幸运的是,这样的有病的现象在OO(面向对象)语言中能够避免了。以下就以Java语言为基础来引入我们本文的主题:工厂模式。

    二、分类
               工厂模式主要是为创建对象提供过渡接口,以便将创建对象的详细过程屏蔽隔离起来,达到提高灵活性的目的。

    工厂模式在《Java与模式》中分为三类:
    1)简单工厂模式(Simple Factory)

    2)工厂方法模式(Factory Method)

    3)抽象工厂模式(Abstract Factory)
                 这三种模式从上到下逐步抽象,而且更具一般性。
                 GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(FactoryMethod)与抽象工厂模式(Abstract Factory)。将简单工厂模式(SimpleFactory)看为工厂方法模式的一种特例,两者归为一类。

    两者皆可,在本文使用《Java与模式》的分类方法。以下来看看这些工厂模式是怎么来“治病”的。

    三、简单工厂模式

    简单工厂模式又称静态工厂方法模式。重命名上就能够看出这个模式一定非常easy。它存在的目的非常easy:定义一个用于创建对象的接口。
           先来看看它的组成:

             1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和推断逻辑。在java中它往往由一个详细类实现。

             2) 抽象产品角色:它通常是详细产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。

             3) 详细产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个详细类实现。
    那么简单工厂模式怎么来使用呢?我们就以简单工厂模式来改造****户坐车的方式——如今****户仅仅须要坐在车里对司机说句:“开车”就能够了。

    代码://抽象产品角色
    public interface Car{
         public void drive();
    }

    //详细产品角色
    public class Benz implements Car{
         public void drive() {
             System.out.println("Driving Benz ");
         }
    }

    public class Bmw implements Car{
         public void drive() {
           System.out.println("Driving Bmw ");
         }
    }
    。。。(奥迪我就不写了:P)

    //工厂类角色
    public class Driver{
               //工厂方法.注意 返回类型为抽象产品角色
                 public static Car driverCar(String s)throws Exception{
                       //推断逻辑,返回详细的产品角色给Client
                       if(s.equalsIgnoreCase("Benz"))
                           return new Benz();
                       else if(s.equalsIgnoreCase("Bmw"))
                               return new Bmw();
                                     ......    
                               else throw new Exception();
                 。。。

    //欢迎****户出场......
    public class Magnate{
                 public static void main(String[] args){
                           try{
                                 //告诉司机我今天坐奔驰                    
                                     Car car = Driver.driverCar("benz");
                                 //下命令:开车                            
                                     car.drive();
                           。。。


             将本程序空缺的其它信息填充完整后就可以执行。假设你将全部的类放在一个文件里,请不要忘记仅仅能有一个类被声明为public。本程序在jdk1.4 下执行通过。
    这便是简单工厂模式了。怎么样,使用起来非常easy吧?那么它带来了什么优点呢?
               首先,使用了简单工厂模式后,我们的程序不在“有病”,更加符合现实中的情况;并且client免除了直接创建产品对象的责任,而只负责“消费”产品(正如****户所为)。

              以下我们从开闭原则(对扩展开放;对改动封闭)上来分析下简单工厂模式。当****户添加�了一辆车的时候,仅仅要符合抽象产品制定的合同,那么仅仅要通知工厂类知道就能够被客户使用了。所以对产品部分来说,它是符合开闭原则的;可是工厂部分好像不太理想,由于每添加�一辆车,都要在工厂类中添加�对应的业务逻辑或者推断逻辑,这显然是违背开闭原则的。可想而知对于新产品的添�,工厂类是非常被动的。对于这种工厂类(在我们的样例中是为司机师傅),我们称它为全能类或者上帝类。
                 我们举的样例是最简单的情况,而在实际应用中,非常可能产品是一个多层次的树状结构。因为简单工厂模式中仅仅有一个工厂类来相应这些产品,所以这可能会把我们的上帝很累了,也很累了我们这些程序猿:(
               于是工厂方法模式作为救世主出现了。
    四、工厂方法模式
                 工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它能够被子类继承。这样在简单工厂模式里集中在工厂方法上的压力能够由工厂方法模式里不同的工厂子类来分担。

    你应该大致猜出了工厂方法模式的结构,来看下它的组成:

           1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是详细工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

           2)详细工厂角色:它含有和详细业务逻辑有关的代码。由应用程序调用以创建相应的详细产品的对象。

           3)抽象产品角色:它是详细产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

           4)详细产品角色:详细工厂角色所创建的对象就是此角色的实例。在java中由详细的类来实现。
          工厂方法模式使用继承自抽象工厂角色的多个子类来取代简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;并且这样使得结构变得灵活起来——当有新的产品(即****户的汽车)产生时,仅仅要依照抽象产品角色、抽象工厂角色提供的合同来生成,那么就能够被客户使用,而不必去改动不论什么已有的代码。能够看出工厂角色的结构也是符合开闭原则的!

          我们还是老规矩,使用一个完整的样例来看看工厂模式各个角色之间是怎样来协调的。话说****户生意越做越大,自己的爱车也越来越多。这可苦了那位司机师傅了,什么车它都要记得,维护,都要经过他来使用!于是****户同情他说:看你跟我这么多年的份上,以后你不用这么辛苦了,我给你分配几个人手,你仅仅管管好他们即可了!于是,工厂方法模式的管理出现了。代码例如以下:

    代码:
    //抽象产品角色,详细产品角色与简单工厂模式类似,仅仅是变得复杂了些,这里略。
    //抽象工厂角色
    public interface Driver{
           public Car driverCar();
    }
    public class BenzDriver implements Driver{
             public Car driverCar(){
                   return new Benz();
             }
    }
    public class BmwDriver implements Driver{
             public Car driverCar(){
               return new Bmw();
             }
    }

    //应该和详细产品形成相应关系...
    //有请****户先生
    public class Magnate{
             public static void main(String[] args){
                         try{
                           Driver driver = new BenzDriver();
                           Car car = driver.driverCar();
                           car.drive();
                         }
                 ……
    }


    能够看出工厂方法的添�,使得对象的数量成倍增长。当产品种类许多时,会出现大量的与之相应的工厂对象,这不是我们所希望的。由于假设不能避免这样的情况,能够考虑使用简单工厂模式与工厂方法模式相结合的方式来降低工厂类:即对于产品树上类似的种类(通常是树的叶子中互为兄弟的)使用简单工厂模式来实现。

    五、小结

    工厂方法模式仿佛已经非常完美的对对象的创建进行了包装,使得客户程序中只处理抽象产品角色提供的接口。那我们是否一定要在代码中遍布工厂呢?大可不必。或许在以下情况下你能够考虑使用工厂方法模式:

         1)当客户程序不须要知道要使用对象的创建过程。

         2)客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个详细的对象。

    简单工厂模式与工厂方法模式真正的避免了代码的改动了?没有。在简单工厂模式中,新产品的添�要改动工厂角色中的推断语句;而在工厂方法模式中,要么将推断逻辑留在抽象工厂角色中,要么在客户程序中将详细工厂角色写死(就象上面的样例一样)。并且产品对象创建条件的改变必定会引起工厂角色的改动。
           面对这样的情况,Java的反射机制与配置文件的巧妙结合突破了限制——这在Spring中完美的体现了出来。
    六、抽象工厂模式

               先来认识下什么是产品族: 位于不同产品等级结构中,功能相关联的产品组成的家族。还是让我们用一个样例来形象地说明一下吧。
    回到抽象工厂模式的话题上。
    能够说,抽象工厂模式和工厂方法模式的差别就在于须要创建对象的复杂程度上。并且抽象工厂模式是三个里面最为抽象、最具一般性的。
    抽象工厂模式的用意为:给client提供一个接口,能够创建多个产品族中的产品对象

    并且使用抽象工厂模式还要满足一下条件:
         1)系统中有多个产品族,而系统一次仅仅可能消费当中一族产品。
         2)同属于同一个产品族的产品以其使用。
    来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):
         1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是详细工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

         2)详细工厂角色:它含有和详细业务逻辑有关的代码。由应用程序调用以创建相应的详细产品的对象。在java中它由详细的类来实现。

         3)抽象产品角色:它是详细产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

         4)详细产品角色:详细工厂角色所创建的对象就是此角色的实例。在java中由详细的类来实现。
    看过了前两个模式,对这个模式各个角色之间的协调情况应该心里有个数了,我就不举详细的样例了。仅仅是一定要注意满足使用抽象工厂模式的条件哦。
    <script type="text/javascript">&lt;!--google_ad_client = &quot;pub-4348265167276910&quot;;/* 468x60, 个人博客 */google_ad_slot = &quot;2046406163&quot;;google_ad_width = 468;google_ad_height = 60;//--&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script><script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script><script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script><script>google_protectAndRun(&quot;ads_core.google_render_ad&quot;, google_handleError, google_render_ad);</script>
  • 相关阅读:
    求连续子数组的最大和
    【LeetCode练习题】Gas Station
    再来看看快速排序
    【LeetCode练习题】First Missing Positive
    【LeetCode练习题】Merge Sorted Array
    Hdu 2089-不要62 数位dp
    Tsinsen A1517. 动态树 树链剖分,线段树,子树操作
    Bzoj 3505: [Cqoi2014]数三角形 数论
    Poj 3695-Rectangles 矩形切割
    Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
  • 原文地址:https://www.cnblogs.com/blfshiye/p/3771186.html
Copyright © 2011-2022 走看看