策略枚举的用法四:枚举工厂

2,325 阅读3分钟

说明

本文只对策略枚举可以使用的场景进行说明,不做其他介绍。提供额外的实现思路。

工厂模式

普通的工厂模式,都有一个基本的抽象类或接口,然后具体的实现类。并且由一个工厂类来进行返回实现类。 参考:工厂模式 在这里插入图片描述

改造

这里对参考的代码进行改造:

  1. Shape.java、Rectangle.java、Square.java、Circle.java,这四个类不变。
  2. 在ShapeFactory.java类中,存在一个类型:"shapeType"。这个就能够使用枚举进行替换。所以我们就新建一个枚举ShapeTypeEnum.java。如下:
  3. 删除将ShapeFactory.java中的getShape方法,使用ShapeTypeEnum.java的valueOf和getShape方法代替。就可以实现工厂模式到策略工厂的转换。
public enum ShapeTypeEnum {

    CIRCLE(new Circle()),
    RECTANGLE(new Rectangle()),
    SQUARE(new Square()),
    ;

    private Shape shape;

    ShapeTypeEnum(Shape shape) {
        this.shape = shape;
    }

    public Shape getShape() {
        return shape;
    }

}
  1. 在使用的地方,代码修改为:
public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      //调用 Circle 的 draw 方法
      shape1.draw();
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
      //调用 Square 的 draw 方法
      shape3.draw();
      System.out.println("***************************************************");
      // 可能存在空指针异常,可以进一步优化 ShapeTypeEnum 类
      ShapeTypeEnum.valueOf("CIRCLE").getShape().draw();
      ShapeTypeEnum.valueOf("RECTANGLE").getShape().draw();
      ShapeTypeEnum.valueOf("SQUARE").getShape().draw();
   }
}

最终结果与原来的一致。

优点

  1. 如果shapeType增加了,我们可以通过修改枚举的时候,马上就能够发现,需要添加一个对应的实现。
  2. 天然的单例实现。如果想要实现多利,也能够通过改造ShapeTypeEnum实现。

缺点

前期代码量会有点大,但是基本属于框架性代码

优化

import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public enum ShapeTypeEnum {

    DEFAULT("", new Default()) {
        @Override
        public Shape getShapeImpl() {
            return new Default();
        }
    },
    CIRCLE("CIRCLE", new Circle()) {
        @Override
        public Shape getShapeImpl() {
            return new Circle();
        }
    },
    RECTANGLE("RECTANGLE", new Rectangle()) {
        @Override
        public Shape getShapeImpl() {
            return new Rectangle();
        }
    },
    SQUARE("SQUARE", new Square()) {
        @Override
        public Shape getShapeImpl() {
            return new Square();
        }
    },
    ;

    /**
     * 功能描述: 获取实现 <br/>
     *
     * @return "com.csdn.enums4.Shape"
     */
    public abstract Shape getShapeImpl();

    /**
     * 功能描述: 单例 <br/>
     *
     * @param type 类型
     * @return "com.csdn.enums4.Shape"
     */
    public static Shape getSingletonShape(String type) {
        return indexOf(type).getShape();
    }

    /**
     * 功能描述: 非单例 <br/>
     *
     * @param type 类型
     * @return "com.csdn.enums4.Shape"
     */
    public static Shape getNonSingletonShape(String type) {
        return indexOf(type).getShapeImpl();
    }

    private final static Map<String, ShapeTypeEnum> map = Stream.of(values()).collect(Collectors.toMap(ShapeTypeEnum::getType, e -> e));

    public static ShapeTypeEnum indexOf(String type) {
        // 避免出现空指针
        return Optional.ofNullable(map.get(type)).orElse(DEFAULT);
    }

    private final String type;
    private final Shape shape;

    ShapeTypeEnum(String type, Shape shape) {
        this.type = type;
        this.shape = shape;
    }

    public String getType() {
        return type;
    }

    public Shape getShape() {
        return shape;
    }

}

每个draw实现的输出,都加上输出当前对象this

   @Override
   public void draw() {
      System.out.println("Inside Default::draw() method." + this);
   }

使用

public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      //调用 Circle 的 draw 方法
      shape1.draw();
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
      //调用 Square 的 draw 方法
      shape3.draw();
      System.out.println("*************************单例****************************");
      ShapeTypeEnum.getSingletonShape("CIRCLE").draw();
      ShapeTypeEnum.getSingletonShape("CIRCLE").draw();
      ShapeTypeEnum.getSingletonShape("RECTANGLE").draw();
      ShapeTypeEnum.getSingletonShape("RECTANGLE").draw();
      ShapeTypeEnum.getSingletonShape("SQUARE").draw();
      ShapeTypeEnum.getSingletonShape("SQUARE").draw();
      System.out.println("**********************非单例*****************************");
      ShapeTypeEnum.getNonSingletonShape("CIRCLE").draw();
      ShapeTypeEnum.getNonSingletonShape("CIRCLE").draw();
      ShapeTypeEnum.getNonSingletonShape("RECTANGLE").draw();
      ShapeTypeEnum.getNonSingletonShape("RECTANGLE").draw();
      ShapeTypeEnum.getNonSingletonShape("SQUARE").draw();
      ShapeTypeEnum.getNonSingletonShape("SQUARE").draw();
   }
}

结果

Inside Circle::draw() method.com.csdn.enums4.Circle@677327b6
Inside Rectangle::draw() method.com.csdn.enums4.Rectangle@14ae5a5
Inside Square::draw() method.com.csdn.enums4.Square@7f31245a
*************************单例****************************
Inside Circle::draw() method.com.csdn.enums4.Circle@5b480cf9
Inside Circle::draw() method.com.csdn.enums4.Circle@5b480cf9
Inside Rectangle::draw() method.com.csdn.enums4.Rectangle@6f496d9f
Inside Rectangle::draw() method.com.csdn.enums4.Rectangle@6f496d9f
Inside Square::draw() method.com.csdn.enums4.Square@723279cf
Inside Square::draw() method.com.csdn.enums4.Square@723279cf
**********************非单例*****************************
Inside Circle::draw() method.com.csdn.enums4.Circle@10f87f48
Inside Circle::draw() method.com.csdn.enums4.Circle@b4c966a
Inside Rectangle::draw() method.com.csdn.enums4.Rectangle@2f4d3709
Inside Rectangle::draw() method.com.csdn.enums4.Rectangle@4e50df2e
Inside Square::draw() method.com.csdn.enums4.Square@1d81eb93
Inside Square::draw() method.com.csdn.enums4.Square@7291c18f