• 设计模式3---工厂模式(Factory Pattern简单工厂、工厂方法、抽象工厂)


    工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类。
    工厂模式的形态
    工厂模式主要用一下几种形态:
    1:简单工厂(Simple Factory)。
    2:工厂方法(Factory Method)。
    3:抽象工厂(Abstract Factory)。

    简单工厂(Simple Factory)
    又叫静态工厂,是工厂模式三中状态中结构最为简单的。主要有一个静态方法,用来接受参数,并根据参数来决定返回实现同一接口的不同类的实例。我们来看一个具体的例子:
    假设一家工厂,几生产洗衣机,有生产冰箱,还有空调等等..
    我们先为所有产品定义一个共同的产品接口

    1. public interface Product{} 


    接着我们让这个工厂的所有产品都必须实现此接口

    1. public class Washer implements Product{ 
    2.    public Washer(){ 
    3.        System.out.println("洗衣机被制造了"); 
    4.    } 
    5.  
    6. public class Icebox implements Product{ 
    7.    public Icebox(){ 
    8.        System.out.println("冰箱被制造了"); 
    9.    } 
    10.  
    11. public class AirCondition implements Product{ 
    12.    public Icebox(){ 
    13.        System.out.println("空调被制造了"); 
    14.    } 


    接下来我们来写一个工厂类,有它来负责生产以上的产品

    1. public class SimpleFactory { 
    2.      
    3.     public static Product factory(String productName) throws Exception{ 
    4.         if(productName.equals("Washer")){ 
    5.             return new Washer(); 
    6.         }else if(productName.equals("Icebox")){ 
    7.             return new Icebox(); 
    8.         }else if(productName.equals("AirCondition")){ 
    9.             return new AirCondition(); 
    10.         }else{ 
    11.             throw new Exception("没有该产品"); 
    12.         } 
    13.     } 


    好了,有了这个工厂类,我们就可以开始下定单了,SimpleFactory将根据不同的定单类决定生产什么产品。

    1. public static void main(String[] args) { 
    2.     try { 
    3.               SimpleFactory.factory("Washer"); 
    4.               SimpleFactory.factory("Icebox"); 
    5.               SimpleFactory.factory("AirCondition"); 
    6.             } catch (Exception e) { 
    7.         e.printStackTrace(); 
    8.     } 


    由上面的代码可以看出,简单工厂的核心就是一个SimpleFactory类,他拥有必要的逻辑判断能力和所有产品的创建权利,我们只需要向把定单给他,就能得到我们想要的产品。这使用起来似乎非常方便。
    但,实际上,这个SimpleFactory有很多的局限。首先,我们每次想要增加一种新产品的时候,都必须修改SimpleFactory的原代码。其次,当我们拥有很多很多产品的时候,而且产品之间又存在复杂的层次关系的时候,这个类必须拥有复杂的逻辑判断能力,其代码量也将不断地激增,这对以后的维护简直就是恐怖两个字...
    还有就是,整个系统都严重依赖SimpleFactory类,只要SimpleFactory类一出问题,系统就进入不能工作的状态,这也是最为致命的一点....
    以上的不足将在工厂模式的另外两种状态中得到解决。

    工厂方法(Factory Method)
    上面的代码告诉我们,简单工厂并不简单,它是整个模式的核心,一旦他出了问题,整个模式都将受影响而不能工作,为了降低风险和为日后的维护、扩展做准备,我们需要对它进行重构,引入工厂方法。
    工厂方法为工厂类定义了接口,用多态来削弱了工厂类的职能,以下是工厂接口的定义:

    1. public interface Factory{ 
    2.   public Product create(); 


    我们再来定义一个产品接口

    1. public interface Product{} 


    一下是实现了产品接口的产品类

    1. public class Washer implements Product{ 
    2.    public Washer(){ 
    3.        System.out.println("洗衣机被制造了"); 
    4.    } 
    5.  
    6. public class Icebox implements Product{ 
    7.    public Icebox(){ 
    8.        System.out.println("冰箱被制造了"); 
    9.    } 
    10.  
    11. public class AirCondition implements Product{ 
    12.    public Icebox(){ 
    13.        System.out.println("空调被制造了"); 
    14.    } 


    接下来,就是工厂方法的核心部分,也就是具体创建产品对象的具体工厂类,

    1. //创建洗衣机的工厂 
    2. public class CreateWasher implements Factory{ 
    3.     public Product create(){ 
    4.           return new Washer(); 
    5.     } 
    6.  
    7. //创建冰箱的工厂 
    8. public class CreateIcebox implements Factory{ 
    9.     public Product create(){ 
    10.           return new Icebox(); 
    11.     } 
    12.  
    13. //创建空调的工厂 
    14. public class CreateAirCondition implements Factory{ 
    15.     public Product create(){ 
    16.           return new AirCondition(); 
    17.     } 


    从上面创建产品对象的代码可以看出,工厂方法和简单工厂的主要区别是,简单工厂是把创建产品的职能都放在一个类里面,而工厂方法则把不同的产品放在实现了工厂接口的不同工厂类里面,这样就算其中一个工厂类出了问题,其他工厂类也能正常工作,互相不受影响,以后增加新产品,也只需要新增一个实现工厂接口工厂类,就能达到,不用修改已有的代码。但工厂方法也有他局限的地方,那就是当面对的产品有复杂的等级结构的时候,例如,工厂除了生产家电外产品,还生产手机产品,这样一来家电是手机就是两大产品家族了,这两大家族下面包含了数量众多的产品,每个产品又有多个型号,这样就形成了一个复杂的产品树了。如果用工厂方法来设计这个产品家族系统,就必须为每个型号的产品创建一个对应的工厂类,当有数百种甚至上千种产品的时候,也必须要有对应的上百成千个工厂类,这就出现了传说的类爆炸,对于以后的维护来说,简直就是一场灾难.....

    抽象工厂(Abstract Factory)
    抽象工厂:意的意图在于创建一系列互相关联或互相依赖的对象。<<Java设计模式>>
    我自己觉得抽象工厂是在工厂方法的基础上引进了分类管理的概念....
    工厂方法用来创建一个产品,它没有分类的概念,而抽象工厂则用于创建一系列产品,所以产品分类成了抽象工厂的重点,
    我们继续用上面的例子来说明:
    工厂生产的所有产品都用都用大写字母来标明它们的型号,比如冰箱,就有“冰箱-A",“冰箱-B",同样,其他的产品也都是遵守这个编号规则,于是就有了一下产品家族树

    冰箱:

        
    1. 冰箱-A  
    2. 冰箱-B



    洗衣机:

        
    1. 洗衣机-A  
    2. 洗衣机-B


    我们可以为冰箱和洗衣机分别定义两个产品接口,以对他们进行分类,

    1. //洗衣机接口 
    2. public interface Washer{ 
    3.  
    4. //冰箱接口 
    5. public interface Icebox{ 


    接着,我们分别创建这两个接口的具体产品

    1. //洗衣机-A 
    2. public class WasherA implements Washer{ 
    3.    public WasherA(){ 
    4.        System.out.println("洗衣机-A被制造了"); 
    5.    } 
    6.  
    7. //洗衣机-B 
    8. public class WasherB implements Washer{ 
    9.    public WasherB(){ 
    10.        System.out.println("洗衣机-B被制造了"); 
    11.    } 
    12.  
    13. //冰箱-A 
    14. public class IceboxA implements Icebox{ 
    15.    public IceboxA(){ 
    16.        System.out.println("冰箱-A被制造了"); 
    17.    } 
    18.  
    19. //冰箱-B 
    20. public class IceboxB implements Icebox{ 
    21.    public IceboxB(){ 
    22.        System.out.println("冰箱-B被制造了"); 
    23.    } 


    到此,产品部分我们准备好了,接下来我们来处理工厂部分,我们先来定义工厂行为接口

    1. public interface Factory{ 
    2.        public Washer createWasher(); 
    3.        public Icebox createIcebox(); 


    接下来我创造具体的工厂类,我们根据上面产品的接口,把型号A的产品分为一类,由一个工厂来管理,把型号为B的产品有另一个工厂管理,根据这个分类,我们可以实现如下的两个具体工厂类

    1. //创建型号为A的产品工厂 
    2. public class FactoryA implements Factory{ 
    3.        //创建洗衣机-A 
    4.        public Washer createWasher(){ 
    5.             return new WasherA(); 
    6.        } 
    7.  
    8.        //创建冰箱-A 
    9.        public Icebox createIcebox(){ 
    10.             return new IceboxA(); 
    11.        } 
    12.  
    13. //创建型号为B的产品工厂 
    14. public class FactoryB implements Factory{ 
    15.        //创建洗衣机-B 
    16.        public Washer createWasher(){ 
    17.             return new WasherB(); 
    18.        } 
    19.  
    20.        //创建冰箱-B 
    21.        public Icebox createIcebox(){ 
    22.             return new IceboxB(); 
    23.        } 

    ===============================================================================

     

     

     

    定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。包括:简单工厂模式,工厂方法模式,抽象工厂模式三种。

    类型:创建类模式

    类图:

    工厂方法模式代码

    [java] view plaincopy
     
     
    1. interface IProduct {  
    2.     public void productMethod();  
    3. }  
    4.   
    5. class Product implements IProduct {  
    6.     public void productMethod() {  
    7.         System.out.println("产品");  
    8.     }  
    9. }  
    10.   
    11. interface IFactory {  
    12.     public IProduct createProduct();  
    13. }  
    14.   
    15. class Factory implements IFactory {  
    16.     public IProduct createProduct() {  
    17.         return new Product();  
    18.     }  
    19. }  
    20.   
    21. public class Client {  
    22.     public static void main(String[] args) {  
    23.         IFactory factory = new Factory();  
    24.         IProduct prodect = factory.createProduct();  
    25.         prodect.productMethod();  
    26.     }  
    27. }  

    工厂模式:

            首先需要说一下工厂模式。工厂模式根据抽象程度的不同分为三种:简单工厂模式(也叫静态工厂模式)、本文所讲述的工厂方法模式、以及抽象工厂模式。工厂模式是编程中经常用到的一种模式。它的主要优点有:

    • 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品。
    • 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
    • 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的。

    工厂方法模式:

           通过工厂方法模式的类图可以看到,工厂方法模式有四个要素:

    • 工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。
    • 工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
    • 产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。
    • 产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。

            前文提到的简单工厂模式跟工厂方法模式极为相似,区别是:简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的。因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算所工厂方法模式的简化版,关于简单工厂模式,在此一笔带过。

          

    适用场景:

            不管是简单工厂模式,工厂方法模式还是抽象工厂模式,他们具有类似的特性,所以他们的适用场景也是类似的。

            首先,作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

           其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。

           再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。

          

    典型应用

           要说明工厂模式的优点,可能没有比组装汽车更合适的例子了。场景是这样的:汽车由发动机、轮、底盘组成,现在需要组装一辆车交给调用者。假如不使用工厂模式,代码如下:

    [java] view plaincopy
     
     
    1. class Engine {  
    2.     public void getStyle(){  
    3.         System.out.println("这是汽车的发动机");  
    4.     }  
    5. }  
    6. class Underpan {  
    7.     public void getStyle(){  
    8.         System.out.println("这是汽车的底盘");  
    9.     }  
    10. }  
    11. class Wheel {  
    12.     public void getStyle(){  
    13.         System.out.println("这是汽车的轮胎");  
    14.     }  
    15. }  
    16. public class Client {  
    17.     public static void main(String[] args) {  
    18.         Engine engine = new Engine();  
    19.         Underpan underpan = new Underpan();  
    20.         Wheel wheel = new Wheel();  
    21.         ICar car = new Car(underpan, wheel, engine);  
    22.         car.show();  
    23.     }  
    24. }  


            可以看到,调用者为了组装汽车还需要另外实例化发动机、底盘和轮胎,而这些汽车的组件是与调用者无关的,严重违反了迪米特法则,耦合度太高。并且非常不利于扩展。另外,本例中发动机、底盘和轮胎还是比较具体的,在实际应用中,可能这些产品的组件也都是抽象的,调用者根本不知道怎样组装产品。假如使用工厂方法的话,整个架构就显得清晰了许多。

    [java] view plaincopy
     
     
    1. interface IFactory {  
    2.     public ICar createCar();  
    3. }  
    4. class Factory implements IFactory {  
    5.     public ICar createCar() {  
    6.         Engine engine = new Engine();  
    7.         Underpan underpan = new Underpan();  
    8.         Wheel wheel = new Wheel();  
    9.         ICar car = new Car(underpan, wheel, engine);  
    10.         return car;  
    11.     }  
    12. }  
    13. public class Client {  
    14.     public static void main(String[] args) {  
    15.         IFactory factory = new Factory();  
    16.         ICar car = factory.createCar();  
    17.         car.show();  
    18.     }  
    19. }  

            使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的,以后如果想组装其他的汽车,只需要再增加一个工厂类的实现就可以。无论是灵活性还是稳定性都得到了极大的提高。

    ==============================================================================

    Java 之工厂方法和抽象工厂模式

    1. 概念

        工厂方法:一抽象产品类派生出多个具体产品类;一抽象工厂类派生出多个具体工厂类;每个具体工厂类只能创建一个具体产品类的实例。

        即定义一个创建对象的接口(即抽象工厂类),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)。“一对一”的关系。

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

        即提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体的类。“一对多”的关系。

    2. UML

     工厂方法:

    抽象工厂:

    3. 代码

    工厂方法:

    复制代码
    public interface Product
    {       
    }
    
    public interface Creator
    {
           public Product factory();
    }
    
    public class ConcreteProduct1 implements Product
    {
           public ConcreteProduct1()
           {
                  System.out.println("ConcreteProduct1被创建");
           }
    }
    
    public class ConcreteProduct2 implements Product
    {
           public ConcreteProduct2()
           {
                  System.out.println("ConcreteProduct2被创建");
           }
     
    }
    
    public class ConcreteCreator1 implements Creator
    {
           public Product factory()
           {
                  return new ConcreteProduct1();
           }
    }
    
    public class ConcreteCreator2 implements Creator
    {
           public Product factory()
           {
                  return new ConcreteProduct2();
           }
    }
     
    public class Client
    {
           private static Creator creator1, creator2;
           private static Product prod1, prod2;
    
           public static void main(String[] args)
           {
                  creator1 = new ConcreteCreator1();
                  prod1 = creator1.factory();
                  System.out.println("----------------------------");
                  creator2 = new ConcreteCreator2();
                  prod2 = creator2.factory();
           }
    }
    复制代码

    抽象工厂:

    复制代码
    //定义不同的产品之间的一定具备的标准,用interface实现 
    //其中的method()方法可看作提取出不同产品的共性,如手机都有类似的功能 
    interface IProductA{ 
      public void method(); 
    } 
    
    interface IProductB{ 
      public void method(); 
    } 
    
    //实现了产品标准实现的一系列具体产品 
    //由于已经设计好A1由厂商1生产,故以下输出代码有“厂商x” 
    class ProductA1 implements IProductA{ 
      public void method() { 
        System.out.println("厂商1    生产ProductA1 ..."); 
      } 
    } 
    
    class ProductA2 implements IProductA{ 
      public void method() { 
        System.out.println("厂商2    生产ProductA2 ..."); 
      } 
    } 
    
    class ProductB1 implements IProductB{ 
      public void method() { 
        System.out.println("厂商1    生产ProductB1 ..."); 
      } 
    } 
    
    class ProductB2 implements IProductB{ 
      public void method() { 
        System.out.println("厂商2    生产ProductB2 ..."); 
      } 
    } 
    
    //每一种牌子的产品生产工厂,即不同的厂商负责自己牌子产品的生产 
    abstract class Factory1{ 
      abstract IProductA getProductA1(); 
      abstract IProductB getProductB1(); 
    } 
    
    abstract class Factory2{ 
      abstract IProductA getProductA2(); 
      abstract IProductB getProductB2(); 
    } 
    
    //具体的工厂用来生产相关的产品 
    class ConcreteFactory1 extends Factory1{ 
      public IProductA getProductA1() { 
        return new ProductA1(); 
      } 
      public IProductB getProductB1() { 
        return new ProductB1(); 
      } 
    } 
    
    class ConcreteFactoryB extends Factory2{ 
      public IProductA getProductA2() { 
        return new ProductA2(); 
      } 
      public IProductB getProductB2() { 
        return new ProductB2(); 
      } 
    } 
    
    //测试类 
    public class Client { 
      public static void main(String[] args) { 
        //厂商1负责生产产品A1、B1 
        Factory1 factory1 = new ConcreteFactory1(); 
        IProductA productA1 = factory1.getProductA1(); 
        IProductB productB1 = factory1.getProductB1(); 
         
        productA1.method(); 
        productB1.method(); 
         
        //厂商2负责生产产品A2、B2 
        Factory2 factory2 = new ConcreteFactoryB(); 
        IProductA productA2 = factory2.getProductA2(); 
        IProductB productB2 = factory2.getProductB2(); 
         
        productA2.method(); 
        productB2.method(); 
      } 
    }
    复制代码

    4. 应用场景

    工厂方法:

    在以下情况下,适用于工厂方法模式:

    (1) 当一个类不知道它所必须创建的对象的类的时候。

    (2) 当一个类希望由它的子类来指定它所创建的对象的时候。

    (3) 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

    抽象工厂:

    (1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。

    (2) 这个系统有多于一个的产品族,而系统只消费其中某一产品族。

    (3) 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。

    (4) 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

  • 相关阅读:
    Mysql5.6主从复制-基于binlog
    mysql 1449 : The user specified as a definer ('root'@'%') does not exist 解决方法
    socket recv阻塞与非阻塞error总结
    linux socket talkclient talkserver示例
    linux-socket connect阻塞和非阻塞模式 示例
    OPENSSL FIPS
    epoll的LT和ET使用EPOLLONESHOT
    如何在socket编程的Tcp连接中实现心跳协议
    linux网络编程:splice函数和tee( )函数高效的零拷贝
    Linux网络编程--sendfile零拷贝高效率发送文件
  • 原文地址:https://www.cnblogs.com/linghu-java/p/5692447.html
Copyright © 2020-2023  润新知