zoukankan      html  css  js  c++  java
  • 设计模式3-工厂模式

    工厂模式分为三种: 简单工厂模式(也叫静态工厂模式)、工厂方法模式、抽象工厂模式。以下会分别介绍这三种工厂模式。

    一、概念

    创建型模式

    工厂模式提供了一种创建对象的最佳方式。它最关心的是最终创建的对象,而不关心创建的过程

    功能:

    • 实例化对象,用工厂方法代替new,实现了创建者和调用者的分离
    • 将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解藕

    二、分类

    1、简单工厂模式(静态工厂模式)

    用来产生同一等级结构中的任意产品。对于增加新的产品,需要修改已有代码。

    效果:

    • 工厂类一般使用静态方法,通过接收的参数来返回不同的对象实例;
    • 增加产品必须修改代码(违反开闭原则OCP:修改关闭,对扩展开放);

    示例(以动物为例)

    1 public interface Animal
    2 {
    3     void eat();  //吃东西
    4     void cry();  //发出声音
    5 }
    View Code

    有两种动物猫和狗:

     1 public class Cat implement Animal
     2 {
     3     public void eat()
     4    {
     5          System.out.println("cat eat fish.");
     6     }
     7     
     8      public void cry()
     9      {
    10            System.out.println("cat cry:miaomiao.");
    11       }
    12 
    13 }
    View Code
     1 public class Dog implement Animal
     2 {
     3     public void eat()
     4    {
     5          System.out.println("dog eat meat.");
     6     }
     7     
     8      public void cry()
     9      {
    10            System.out.println("dog cry:汪汪.");
    11       }
    12 
    13 }
    View Code

    有个宠物店,接收各种动物:

     1 public class PetShop
     2 {
     3     public static Animal getAnimal(String name)
     4     {
     5           if("cat".equalsIgnoreCase(name)
     6           {
     7                return new Cat();
     8           }
     9           else if("dog".equalsIgnoreCase(name)
    10           {
    11                return new Dog();
    12           }
    13           else
    14           {
    15              .......
    16           }
    17     }
    18 }
    View Code

    调用示例:

    public static void main(String[] args)
    {
        Animal cat = PetShop.getAnimal("cat");
        cat.eat();
        Animal dog = PetShop.getAnimal("dog");
        dog.eat();
    }
    View Code

    从示例中就可以看出,自己无需去new对象,通过PetShop就可以获取对象,这样使用方就和产品之间就降低了耦合度

    代码模块职责更明确了,有专门的消费模块,有专门的生产模块。

    但若增加另一种动物,则必须修改PetShop中的代码,每增加一种都必须再PetShop中增加一个else if, 这样很是不便,对此我们可以将PetShop改为通过反射的方式获取对象:

    1 public class PetShop
    2 {
    3     public static Animal getAnimal(String namePath) throws Exception
    4     {
    5         Class<?> c = Class.forName(namePath);
    6         return (Animal)c.newInstance();       
    7     }
    8 }

    调用的地方改为:

    1 public static void main(String[] args) throws Exception
    2 {
    3     Animal dog = PetShop.getAnimal("com.frieda.animalFactory.Dog");
    4     dog.eat();
    5     Animal cat = PetShop.getAnimal("com.frieda.animalFactory.Cat");
    6     cat.cry();
    7 }

    但这样做的弊端是,项目重构,类路径,包路径改变,这样更改的地方有点多;但可以通过将所有的类路径放入inerface中后者properties文件或者xml文件中,后期遇到修改路径的, 直接修改改文件即可。

    从设计模式的角度讲,这么修改也有很大的优点。现在不管我新增还是删除动物,宠物店(类工厂)都不用变了,只需要告诉工厂我需要哪种动物就够了,工厂自然会给调用者返回。这种写法,也是Spring的基础。

    2、工厂方法模式

    用来产生同一等级结构中的固定产品。支持增加任意产品。

    效果:

    • 避免简单工厂的缺点,但不完全满足OCP;
    • 定义一个创建产品对象的工厂接口,将实际创建推迟到子类中(简单工厂中的具体工厂类拆成:抽象工厂类层+具体的工厂类层,即产品抽象,工厂也抽象
    • 简单工厂模式VS工厂方法模式:
    • i. 结构复杂度:显然简单工厂模式占优,简单工厂模式只要一个工厂,而工厂方法模式的工厂类随着产品类个数增加而增加。
      ii. 代码复杂度:代码复杂度与结构复杂度相反,简单工厂模式的工厂类随着产品增加需要增加更多方法(代码),而工厂方法模式每个具体工厂类只完成单一任务,代码简单。
      iii. 客户端编程难度:工厂方法模式虽然满足了OCP,但客户端编码中需要对工厂实例化,而简单工厂模式的工厂类是一个静态类。
      iv. 管理上的难度:工厂方法模式需要维护的工厂类过多,而简单工厂模式只有一个。
    • 设计理论建议使用工厂方法模式,但实践中往往采用的是简单工厂模式。

    借用下他人的图来看下工厂方法模式: 

     示例:

    Car.java

    1 public interface Car {
    2 
    3     void run();
    4     
    5 }
    View Code

    CarFactory.java

    1 public interface CarFactory {
    2 
    3     Car createCar();
    4     
    5 }
    View Code

    Audi.java

    1 public class Audi implements Car {
    2 
    3     @Override
    4     public void run() {
    5         System.out.println("奥迪在跑!");
    6     }
    7 
    8 }
    View Code

    AudiFactory.java

    1 public class AudiFactory implements CarFactory {
    2 
    3     @Override
    4     public Car createCar() {
    5         return new Audi();
    6     }
    7 
    8 }
    View Code

    Jeep.java

    1 public class Jeep implements Car {
    2 
    3     @Override
    4     public void run() {
    5         System.out.println("吉普在跑!");
    6     }
    7 
    8 }
    View Code

    JeepFactory.java

    1 public class JeepFactory implements CarFactory {
    2 
    3     @Override
    4     public Car createCar() {
    5         return new Jeep();
    6     }
    7 
    8 }
    View Code

    调用示例:

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         Car car1 = new AudiFactory().createCar();
     5         Car car2 = new JeepFactory().createCar();
     6         car1.run();
     7         car2.run();
     8     }
     9 
    10 }

    3、抽象工厂模式

    用来生产不同产品族的全部产品。对于增加新的产品,无能为力:支持增加产品族。

    效果:

    抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种,业务分类时,通过抽象共产模式产生需要的对象时一种非常好的解决方式。

     示例:

    Shape,java(interface)

    public interface Shape {
       void draw();
    }
    View Code

    Rectangle.java

    public class Rectangle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
    View Code

    Square,java

    public class Square implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Square::draw() method.");
       }
    }
    View Code

    Circle.java

    public class Circle implements Shape {
     
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    View Code

    Color.java(interface)

    public interface Color {
       void fill();
    }
    View Code

    Red.java

    public class Red implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Red::fill() method.");
       }
    }
    View Code

    Green.java

    public class Green implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Green::fill() method.");
       }
    }
    View Code

    Blue.java

    public class Blue implements Color {
     
       @Override
       public void fill() {
          System.out.println("Inside Blue::fill() method.");
       }
    }
    View Code

    为 Color 和 Shape 对象创建抽象类来获取工厂。

    AbstractFactory.java

    public abstract class AbstractFactory {
       public abstract Color getColor(String color);
       public abstract Shape getShape(String shape) ;
    }
    View Code

    创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。

    ShapeFactory.java

    public class ShapeFactory extends AbstractFactory {
        
       @Override
       public Shape getShape(String shapeType){
          if(shapeType == null){
             return null;
          }        
          if(shapeType.equalsIgnoreCase("CIRCLE")){
             return new Circle();
          } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
             return new Rectangle();
          } else if(shapeType.equalsIgnoreCase("SQUARE")){
             return new Square();
          }
          return null;
       }
       
       @Override
       public Color getColor(String color) {
          return null;
       }
    }
    View Code

    ColorFactory.java

    public class ColorFactory extends AbstractFactory {
        
       @Override
       public Shape getShape(String shapeType){
          return null;
       }
       
       @Override
       public Color getColor(String color) {
          if(color == null){
             return null;
          }        
          if(color.equalsIgnoreCase("RED")){
             return new Red();
          } else if(color.equalsIgnoreCase("GREEN")){
             return new Green();
          } else if(color.equalsIgnoreCase("BLUE")){
             return new Blue();
          }
          return null;
       }
    }
    View Code

    创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。

    public class FactoryProducer {
       public static AbstractFactory getFactory(String choice){
          if(choice.equalsIgnoreCase("SHAPE")){
             return new ShapeFactory();
          } else if(choice.equalsIgnoreCase("COLOR")){
             return new ColorFactory();
          }
          return null;
       }
    }
    View Code

    使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。

    AbstractFactoryPatternDemo.java

    public class AbstractFactoryPatternDemo {
       public static void main(String[] args) {
     
          //获取形状工厂
          AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
     
          //获取形状为 Circle 的对象
          Shape shape1 = shapeFactory.getShape("CIRCLE");
     
          //调用 Circle 的 draw 方法
          shape1.draw();
     
          //获取形状为 Rectangle 的对象
          Shape shape2 = shapeFactory.getShape("RECTANGLE");
     
          //调用 Rectangle 的 draw 方法
          shape2.draw();
          
          //获取形状为 Square 的对象
          Shape shape3 = shapeFactory.getShape("SQUARE");
     
          //调用 Square 的 draw 方法
          shape3.draw();
     
          //获取颜色工厂
          AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
     
          //获取颜色为 Red 的对象
          Color color1 = colorFactory.getColor("RED");
     
          //调用 Red 的 fill 方法
          color1.fill();
     
          //获取颜色为 Green 的对象
          Color color2 = colorFactory.getColor("Green");
     
          //调用 Green 的 fill 方法
          color2.fill();
     
          //获取颜色为 Blue 的对象
          Color color3 = colorFactory.getColor("BLUE");
     
          //调用 Blue 的 fill 方法
          color3.fill();
       }
    }
    View Code

    上述示例结构如下:

     

    三、工厂模式在Java中的应用及解读

    简单工厂模式在Java中的应用

    线程池

    ThreadPoolExecutor类中有四个构造方法

    public class ThreadPoolExecutor extends AbstractExecutorService {
        .....
        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                BlockingQueue<Runnable> workQueue);
     
        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
     
        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
     
        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
        ...
    }
    View Code

    从构造方法的传参看到需要很多参数才能创建对象,但这里的部分参数尤其是后面3个参数基本上用默认值,而不需要每次传入。

    再看下线程池的工厂模式(都是使用静态工厂模式创建对象)

    Executors.newCachedThreadPool();       //创建一个无界限缓冲池,缓冲池容量大小为Integer.MAX_VALUE
    Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
    Executors.newFixedThreadPool(int);     //创建固定容量大小的缓冲池

    具体实现如下:

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    View Code

    是不是都已经传入一些默认值,这让我们无需再思考在构造函数中应该传入什么值而苦恼,而直接通过工厂模式获取一个对象。

    工厂方法模式在Java中的应用: 

    ThreadFactory,一个生产线程的接口;

    public interface ThreadFactory {
    
        /**
         * Constructs a new {@code Thread}.  Implementations may also initialize
         * priority, name, daemon status, {@code ThreadGroup}, etc.
         *
         * @param r a runnable to be executed by new thread instance
         * @return constructed thread, or {@code null} if the request to
         *         create a thread is rejected
         */
        Thread newThread(Runnable r);
    }
    View Code

    具体的线程工厂可以implements这个接口并实现newThread(Runnable r)方法,来生产具体线程工厂想要生产的线程。JDK在Executors给开发者提供了一个静态内部类DefaultThreadFactory,当然开发者也可以自行实现这个接口,写自定义的线程工厂。

    抽象工厂模式在Java中的应用:

    java.sql.Connection

    public interface Connection {
        //提供一个执行对象
        Statement createStatement() throws SQLException;
        //提供一个支持预编译的执行对象
        PreparedStatement prepareStatement(String sql) throws SQLException;
        //提供一个支持存储过程的执行对象
        CallableStatement prepareCall(String sql) throws SQLException;
    }

    可以看的出来Connection就是一个经典的抽象工厂,而Statement,PreparedStatement,CallableStatement是这个抽象工厂提供的三个抽象产品,其中Driver起到Client的作用我们只需要把Driver注册进DriverManager就可以为我们生成需要的Connection每次操作数据库只需要使用java提供的这套接口就可以而不需要考虑我们使用的是什么SQL数据库(不考虑特殊SQL语法的情况下)。

     这些抽象工厂与抽象产品均由对应的数据库驱动实现,下面用MySQL与Oracle的驱动进行举例。

      

    JDBC抽象工厂UML图

  • 相关阅读:
    hdu2604 矩阵快速幂
    自己对有上下界的网络流的理解
    自己对有上下界的网络流的理解
    POJ 2396 构造矩阵(上下流)
    POJ 2396 构造矩阵(上下流)
    hdu4940 有上下界的无源可行流判断
    hdu4940 有上下界的无源可行流判断
    hdu4515 小模拟
    hdu4515 小模拟
    hdu4901 枚举状态(找集合对S(xor) ==T(and))
  • 原文地址:https://www.cnblogs.com/dudu2mama/p/14145255.html
Copyright © 2011-2022 走看看