设计模式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图

 

 

posted @ 2020-12-18 14:58  工作中的点点滴滴  阅读(98)  评论(0编辑  收藏  举报