最全工厂设计模式案例详解,不服来辩!

2022-12-02 20:17:39 浏览数 (1)

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,今天我们一起来彻底解析一下它。

一、介绍

从名称上,顾名思义就是创建产品,按类别分为简单工厂模式工厂方法模式抽象工厂模式,主要功能都是帮助我们把对象的实例化操作单独抽取出来,优化系统架构,增强系统的扩展性。

下面,我们一起来看看各个模式的使用方式。

二、简单工厂模式

简单工厂模式,对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象。

  • 创建一个接口
代码语言:javascript复制
public interface Product {
   void operation1();
   void operation2();
}
  • 创建实现接口的实体类
代码语言:javascript复制
public class ConcreateProductA implements Product{

   @Override
   public void operation1() {
      System.out.println("产品A,执行任务1");
   }
   
   @Override
   public void operation2() {
      System.out.println("产品A,执行任务2");
   }
}
代码语言:javascript复制
public class ConcreateProductB implements Product{

   @Override
   public void operation1() {
      System.out.println("产品B,执行任务1");
   }
   
   @Override
   public void operation2() {
      System.out.println("产品B,执行任务2");
   }
}
  • 创建一个工厂,生成基于给定信息的实体类的对象
代码语言:javascript复制
public class SimpleFactory {
    
   //使用 create 方法获取形状类型的对象
   public Product create(String productType){
      if(productType == null){
         return null;
      }
      if(productType.equalsIgnoreCase("productA")){
         return new ConcreateProductA();
      }
      if(productType.equalsIgnoreCase("productB")){
         return new ConcreateProductB();
      }
      return null;
   }
}
  • 编写客户端测试类,使用该工厂,通过传递类型信息来获取实体类的对象
代码语言:javascript复制
public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      SimpleFactory simpleFactory = new SimpleFactory();
      
      //获取 productA 的对象
      Product productA = simpleFactory.create("productA");
 
      //调用 productA 的 operation1、operation2 方法
      productA.operation1();
      productA.operation2();
 
      //获取 productB 的对象
      Product productB = simpleFactory.create("productB");
 
      //调用 productB 的 operation1、operation2 方法
      productB.operation1();
      productB.operation2();
   }
}
  • 执行程序,输出结果:
代码语言:javascript复制
产品A,执行任务1
产品A,执行任务2
产品B,执行任务1
产品B,执行任务2

当然,还可以将创建对象方式进行改进,将SimpleFactory类创建对象的方式改成如下方式:

代码语言:javascript复制
public class SimpleFactory {
    
   //反射机制获取实体类
   public <T> T createByClazzName(Class<? extends T> clazz){
  T obj = null;
  try {
   obj = (T) Class.forName(clazz.getName()).newInstance();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return obj;
 }
}

这样做的好处是,当有新的产品加入时,不用修改工厂类,在调用的时候,采用如下方式即可获取对象!

代码语言:javascript复制
Product product = new SimpleFactory().create("类名.class");

三、工厂方法模式

和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂。

  • 创建一个工厂接口
代码语言:javascript复制
public interface FactoryProduct {
   Product create();
}
  • 创建实现接口的实体类
代码语言:javascript复制
public class ConcreateFactoryA implements FactoryProduct{

   @Override
   public Product create() {
      return new ConcreateProductA();
   }
}
代码语言:javascript复制
public class ConcreateFactoryB implements FactoryProduct{

   @Override
   public Product create() {
      return new ConcreateProductB();
   }
}
  • 编写客户端测试类,使用该工厂,通过传递类型信息来获取实体类的对象
代码语言:javascript复制
public class FactoryPatternDemo {

   public static void main(String[] args) {

      //获取 productA 的对象
      Product productA = new ConcreateFactoryA().create();

      //调用 productA 的 operation1、operation2 方法
      productA.operation1();
      productA.operation2();

      //获取 productB 的对象
      Product productA = new ConcreateFactoryB().create();

      //调用 productB 的 operation1、operation2 方法
      productB.operation1();
      productB.operation2();
   }
}
  • 执行程序,输出结果:
代码语言:javascript复制
产品A,执行任务1
产品A,执行任务2
产品B,执行任务1
产品B,执行任务2

四、抽象工厂模式

抽象工厂模式主要是应对产品族概念提出来的。提供一个创建一系列相关或相互依赖的对象。

  • 为形状创建一个接口
代码语言:javascript复制
public interface Shape {
   void draw();
}
  • 创建实现接口的实体类
代码语言:javascript复制
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
代码语言:javascript复制
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
代码语言:javascript复制
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
  • 为颜色创建一个接口
代码语言:javascript复制
public interface Color {
   void fill();
}
  • 创建实现接口的实体类
代码语言:javascript复制
public class Red implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Red::fill() method.");
   }
}
代码语言:javascript复制
public class Green implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Green::fill() method.");
   }
}
代码语言:javascript复制
public class Blue implements Color {
 
   @Override
   public void fill() {
      System.out.println("Inside Blue::fill() method.");
   }
}
  • 为 Color 和 Shape 对象创建抽象类来获取工厂
代码语言:javascript复制
public abstract class AbstractFactory {
   public abstract Color getColor(String color);
   public abstract Shape getShape(String shape) ;
}
  • 创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象
代码语言:javascript复制
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;
   }
}
代码语言:javascript复制
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;
   }
}
  • 创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂
代码语言:javascript复制
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;
   }
}
  • 使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象
代码语言:javascript复制
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();
   }
}
  • 执行程序,输出结果:
代码语言:javascript复制
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.

五、应用

工厂模式在实际开发中使用非常频繁,例如 JDK 中的日历操作,在国际化的时候,获取本地语言就用到简单工厂模式。

写一个获取测试,如下:

代码语言:javascript复制
public static void main(String[] args) {
    //获取日历操作类
    Calendar calendar = Calendar.getInstance();

    int year = calendar.get(Calendar.YEAR);
    // 取月份要加1
    int month = calendar.get(Calendar.MONTH)   1;
    int day = calendar.get(Calendar.DAY_OF_MONTH);
    int hour = calendar.get(Calendar.HOUR_OF_DAY);
    int minute = calendar.get(Calendar.MINUTE);
    int seconds = calendar.get(Calendar.SECOND);
    // 1-7分别代表 -- 星期日,星期一,星期二,星期三,星期四,星期五,星期六
    int week = calendar.get(calendar.DAY_OF_WEEK);

    // 年-月-日
    System.out.println("year = "   year);
    System.out.println("month = "   month);
    System.out.println("day = "   day);
    //时-分-秒
    System.out.println("hour = "   hour);
    System.out.println("minute = "   minute);
    System.out.println("seconds = "   seconds);

    // 星期
    System.out.println("week = "   week);
}

进入getInstance()方法,在获取日历类型的时候,内容如下:

六、小结

工厂模式中,重要的是工厂类,而不是产品类。产品类可以是多种形式,多层继承或者是单个类都是可以的。

但要明确的,工厂模式的接口只会返回一种类型的实例,这是在设计产品类的时候需要注意的,最好是有父类或者共同实现的接口。

上面介绍的三种工厂模式有各自的应用场景,实际应用时能解决问题满足需求即可!

七、参考

1、菜鸟教程 - 工厂模式

2、博客园 - alpha_panda - 设计模式之工厂模

0 人点赞