工厂设计模式

来源:互联网 发布:自然语言处理数据挖掘 编辑:程序博客网 时间:2024/06/04 17:50

工厂模式定义:提供创建对象的接口.

  为何使用? 
  工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。 
  为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。 
  我们以类Sample为例, 如果我们要创建Sample的实例对象:    Sample sample=new Sample(); 
  可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值 查询数据库等。 
  首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成: 
  Sample sample=new Sample(参数); 
  但是,如果创建sample实例时所做的初始化工作不是象赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了(就需要Refactor重整)。 
  为什么说代码很难看,初学者可能没有这种感觉,我们分析如下,初始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java面向对象的原则,面向对象的封装(Encapsulation)和分派
(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间偶合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。 
  在本例中,首先,我们需要将创建实例的工作与使用实例的工作分开, 也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。


工厂模式有三种:简单工厂模式、工厂方法模式、抽象工厂模式

  1. 简单工厂
    定义:类创建模式,用来创建其他类的实例,通过不同的特征返回不同类的实例,被返回类具有相同的父类
    角色: 产品的父类
    产品的具体类
    工厂类  
    优点:  
    (1)工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。  
    (2)客户端无需知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。  (3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。  
    缺点:  
    (1)由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。  
    (2)使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。  
    (3)系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。  
    (4)简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。  
      
    简单工厂模式的适用环境 : 
    (1)工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂;  
    (2)客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。 

    代码示例:
    [java] view plaincopy
    1. /** 
    2.  * 产品的父类 
    3.  * @author sky 
    4.  * 
    5.  */  
    6. public interface Job {  
    7.       
    8.     public void work();  
    9.   
    10. }  
    11.   
    12.   
    13. /** 
    14.  * 产品的具体子类 
    15.  * @author sky 
    16.  */  
    17. public class Teacher implements Job {  
    18.     @Override  
    19.     public void work() {  
    20.         System.out.println("I'm teaching...");  
    21.     }  
    22. }  
    23.   
    24. /** 
    25.  * 产品的具体子类2 
    26.  * @author sky 
    27.  */  
    28. public class Programer implements Job {  
    29.   
    30.     @Override  
    31.     public void work() {  
    32.         System.out.println("I'm Programing...");  
    33.     }  
    34.   
    35. }  
    36.   
    37. /** 
    38.  * 工厂类 
    39.  * @author sky 
    40.  */  
    41. public class JobFactory {  
    42.       
    43.     public static final int PROGRAMER = 1;  
    44.       
    45.     public static final int TEACHER = 2;  
    46.       
    47.     public static Job create(int identity){  
    48.         if(identity==PROGRAMER){  
    49.             return new Programer();  
    50.         }else if(identity==TEACHER){  
    51.             return new Teacher();  
    52.         }else{  
    53.             return null;  
    54.         }  
    55.     }  
    56.   
    57. }  
    58.   
    59. /** 
    60.  * 测试类 
    61.  * @author sky 
    62.  */  
    63. public class Test {  
    64.   
    65.     /** 
    66.      * @param args 
    67.      */  
    68.     public static void main(String[] args) {  
    69.         System.out.println("创建程序员:");  
    70.         Job job = JobFactory.create(JobFactory.PROGRAMER);  
    71.         job.work();  
    72.         System.out.println("创建老师:");  
    73.         job =JobFactory.create(JobFactory.TEACHER);  
    74.         job.work();  
    75.     }  
    76.   
    77. }  
    78.   
    79. 输出:  
    80.     创建程序员:  
    81.     I'm Programing...  
    82.     创建老师:  
    83.     I'm teaching...  


  2. 工厂方法
    定义:定义一个用于创建对象的接口,使类得实例化延迟到之类,由子类来决定实例化哪一个类。
    在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做。这个核心工厂则变为抽象工厂角色,仅负责给出具工厂子类必须实现的接口,而不接触哪一产品创建的细节。
    这种抽象的结果,使这种工厂方法模式可以用来允许系统不修改具体工厂角色的情况下引进新产品,这一特点无疑使得工厂模式具有超过简单工厂模式的优越性。
    角色: 工厂接口
    工厂具体子类
    产品接口
    产品具体子类
    使用心得:如果一个对象有许多的子类,但是子类可以划为几类,这时,如果使用简单工厂模式,则会使代码过多,逻辑混乱,此时使用工厂方法则能让代码更有层次感,条例分明。例如,工作可以分为程序员,教师等,程序员又可分为java程序员,C++程序员,教师又可分为语文老师,数学老师,此种情况下使用工厂方法模式比较合适
    优点:  
    (1)在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名。  
    (2)基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,正是因为所有的具体工厂类都具有同一抽象父类。  
    (3)使用工厂方法模式的另一个优点是在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。  
    缺点:  
    (1)在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。  
    (2)由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。  
      
    工厂方法模式的适用环境 :  
    (1)一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。  
    (2)一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。  
    (3)将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。 

    代码示例:
    [java] view plaincopy
    1. /** 
    2.  * 产品的父类 
    3.  * @author sky 
    4.  * 
    5.  */  
    6. public interface Job {  
    7.       
    8.     public void work();  
    9.   
    10. }  
    11.   
    12. /** 
    13.  * 产品的具体子类1 
    14.  * @author sky 
    15.  */  
    16. public class ChineseTeacher implements Job {  
    17.   
    18.     @Override  
    19.     public void work() {  
    20.         System.out.println("I'm a chinese teacher");  
    21.     }  
    22.   
    23. }  
    24.   
    25. /** 
    26.  * 产品的具体子类2 
    27.  * @author sky 
    28.  */  
    29. public class MathTeacher implements Job {  
    30.   
    31.     @Override  
    32.     public void work() {  
    33.         System.out.println("I'm a math teacher");  
    34.     }  
    35.   
    36. }  
    37.   
    38. /** 
    39.  * 产品的具体子类3 
    40.  * @author sky 
    41.  */  
    42. public class CProgramer implements Job {  
    43.   
    44.     @Override  
    45.     public void work() {  
    46.         System.out.println("I'm a C programer");  
    47.     }  
    48.   
    49. }  
    50.   
    51. /** 
    52.  * 产品的具体子类4 
    53.  * @author sky 
    54.  */  
    55. public class JavaProgramer implements Job {  
    56.   
    57.     @Override  
    58.     public void work() {  
    59.         System.out.println("I'm a java programer");  
    60.     }  
    61.   
    62. }  
    63.   
    64. /** 
    65.  * 工厂接口 
    66.  * @author sky 
    67.  * 
    68.  */  
    69. public interface JobFactory {  
    70.       
    71.     public Job create(int type);  
    72.   
    73. }  
    74.   
    75. /** 
    76.  * 工厂具体子类1 程序员工厂 
    77.  * @author sky 
    78.  */  
    79. public class ProgramerFactory implements JobFactory {  
    80.   
    81.     public static final int JAVA = 1;  
    82.       
    83.     public static final int C = 2;  
    84.   
    85.     @Override  
    86.     public Job create(int type) {  
    87.   
    88.         if(type == JAVA){  
    89.             return new JavaProgramer();  
    90.         }else if(type == C){  
    91.             return new CProgramer();  
    92.         }  
    93.         return null;  
    94.     }  
    95.   
    96. }  
    97.   
    98. /** 
    99.  * 工厂具体子类2 教师工厂 
    100.  * @author sky 
    101.  */  
    102. public class TeacherFactory implements JobFactory {  
    103.   
    104.     public static final int MATH = 1;  
    105.       
    106.     public static final int CHINESE = 2;  
    107.   
    108.     @Override  
    109.     public Job create(int type) {  
    110.   
    111.         if(type == MATH){  
    112.             return new MathTeacher();  
    113.         }else if(type == CHINESE){  
    114.             return new ChineseTeacher();  
    115.         }  
    116.         return null;  
    117.     }  
    118.   
    119. }  
    120.   
    121. /** 
    122.  * 测试代码 
    123.  * @author sky 
    124.  */  
    125. public class Test {  
    126.   
    127.     public static void main(String[] args) {  
    128.         System.out.println("请创建一个java程序员");  
    129.         JobFactory jf = new ProgramerFactory();  
    130.         Job job = jf.create(ProgramerFactory.JAVA);  
    131.         job.work();  
    132.         System.out.println("请创建一个C程序员");  
    133.         job = jf.create(ProgramerFactory.C);  
    134.         job.work();  
    135.         jf = new TeacherFactory();  
    136.         System.out.println("请创建一个语文老师");  
    137.         job = jf.create(TeacherFactory.CHINESE);  
    138.         job.work();  
    139.         System.out.println("请创建一个数学老师");  
    140.         job = jf.create(TeacherFactory.MATH);  
    141.         job.work();  
    142.     }  
    143.   
    144. }  
    145.   
    146. 输出:  
    147.     请创建一个java程序员  
    148.     I'm a java programer  
    149.     请创建一个C程序员  
    150.     I'm a C programer  
    151.     请创建一个语文老师  
    152.     I'm a chinese teacher  
    153.     请创建一个数学老师  
    154.     I'm a math teacher  
  3. 抽象工厂
    定义:提供一个接口,创建一系列相关连的产品(产品族),而不必指定具体的类。通常,产品族是某个产品的组成部分,比如一个电脑的CPU,内测,硬盘等,一个开发团队的前端、后端、美工等


    角色: 工厂接口
        工厂具体子类
        产品接口
      产品具体子类
     抽象工厂模式的优缺点  
    优点:  
    (1) 隔离了具体类的生成,使得用户不需要知道什么被创建了。  
    (2) 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。  
    缺点:  
    (1)添加新的产品对像时,难以扩展抽象工厂以便生产新种类的产品。  
      
     抽象工厂模式的适用环境 : 
    (1)一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。这对于所有形态的工厂模式都是重要的;  
    (2)一个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品;  
    (3)同属于同一个产品族的产品是在一起使用的,这一约束必须要在系统的设计中体现出来;  
    (4)系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

    代码示例:
    [java] view plaincopy
    1. /** 
    2.  * 前端接口 
    3.  * @author sky 
    4.  */  
    5. public interface Client {  
    6.   
    7.     public void doClient();  
    8. }  
    9.   
    10. /** 
    11.  * 前端具体子类 
    12.  * @author sky 
    13.  */  
    14. public class JuniorClient implements Client {  
    15.   
    16.     @Override  
    17.     public void doClient() {  
    18.         System.out.println("I'm a junior client");  
    19.     }  
    20.   
    21. }  
    22.   
    23. /** 
    24.  * 后端接口 
    25.  * @author sky 
    26.  */  
    27. public interface Server {  
    28.   
    29.     public void doServer();  
    30. }  
    31.   
    32. /** 
    33.  *后端具体子类 
    34.  * @author sky 
    35.  */  
    36. public class JuniorServer implements Server {  
    37.   
    38.     @Override  
    39.     public void doServer() {  
    40.         System.out.println("I'm a junior server");  
    41.     }  
    42.   
    43. }  
    44.   
    45. /** 
    46.  * 团队工厂接口 
    47.  * @author sky 
    48.  */  
    49. public interface TeamFactory {  
    50.   
    51.     /** 
    52.      * 创建客户端,如果有多个对象选择,这里可以添加参数,子类中根据具体的参数返回对应的对象 
    53.      * @return 
    54.      */  
    55.     public Client createClient();  
    56.       
    57.     /** 
    58.      * 创建服务端,如果有多个对象选择,这里可以添加参数,子类中根据具体的参数返回对应的对象 
    59.      * @return 
    60.      */  
    61.     public Server createServer();  
    62. }  
    63.   
    64. /** 
    65.  * 团队工厂具体子类 
    66.  * @author sky 
    67.  */  
    68. public class JuniorTeamFactory implements TeamFactory {  
    69.   
    70.     @Override  
    71.     public Client createClient() {  
    72.         return new JuniorClient();  
    73.     }  
    74.   
    75.     @Override  
    76.     public Server createServer() {  
    77.         return new JuniorServer();  
    78.     }  
    79.   
    80. }  
    81.   
    82. /** 
    83.  * 测试类 
    84.  * @author sky 
    85.  */  
    86. public class Test {  
    87.   
    88.     public static void main(String[] args) {  
    89.         System.out.println("我要创建一个初级团队,包括一个初级前端,一个初级服务端");  
    90.         TeamFactory tf = new JuniorTeamFactory();  
    91.         Client client = tf.createClient();  
    92.         Server server = tf.createServer();  
    93.         client.doClient();  
    94.         server.doServer();  
    95.     }  
    96.   
    97. }  
    98.   
    99. 输出:  
    100.     我要创建一个初级团队,包括一个初级前端,一个初级服务端  
    101.     I'm a junior client  
    102.     I'm a junior server 


工厂方法模式:

一个抽象产品类,可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
一个抽象工厂类,可以派生出多个具体工厂类。   
每个具体工厂类可以创建多个具体产品类的实例。   
    
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
0 0
原创粉丝点击