工厂模式是JAVA中最常用的设计模式之一,这种设计模式属于创建性模式,是一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用同一个接口来指向新创建的对象例如:你在买一辆车时并不需要这辆车的具体实现,只要从工厂里直接提货就好。

我们来举一个简单的栗子体会一下工厂模式的含义,在这个栗子中我们创建一个形状接口及其实现类,还有一个工厂类。

第一步:创建接口Shape.java

public interface Shape {
    void draw();
}

第二步:创建Shape.java的实现类

Circle.java

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

Rectangle.java

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

Square.java

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

第三步:创建一个工厂ShapeFactory1.java

public class ShapeFactory1 {

    private final String CIRCLE = "CIRCLE";
    private final String RECTANGLE = "RECTANGLE";
    private final String SQUARE = "SQUARE";

    /**
     * 使用getShape()获取形状类型对象
     * @param shapeType
     * @return
     */
    public Shape getShape(String shapeType){
        if(StringUtils.isEmpty(shapeType)){
            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;
    }
}

第四步:使用该工厂来创建对象

public class FactoryPatternDemo1 {
    public static void main(String[] args) {
        ShapeFactory1 factory1 = new ShapeFactory1();

        //获取circle对象
        Shape shape1 = factory1.getShape("circle");
        shape1.draw();

        //获取Rectangle对象
        Shape shape2 = factory1.getShape("Rectangle");
        shape2.draw();

        //获取Square对象
        Shape shape3 = factory1.getShape("Square");
        shape3.draw();
    }
}

第五步:验证输出

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

由此总结工厂模式的优缺点:

优点:

1、一个调用者只要知道其名字就可以,不需要知道其创建过程;

2、拓展性高:增加产品时只需要拓展一个工厂类就好了。

缺点:

每次增加一个产品就要新增一个具体类和实现工厂,使得系统中类的个数成倍增加,一定程度上增加了系统的复杂度。

所以,我们在创建复杂对象时适合使用工厂模式,创建简单对象时使用new关键字来创建

-----------------------------------------------我是一条分割线-----------------------------------------------

上面的代码中存在一个很大的问题:每增加一个实现类就要修改ShapeFactory1.java的代码,这样是及其不正确的做法,为了解决这个问题,我们使用反射机制来改进。

升级版本一:

工厂类:

public class ShapeFactory2 {

    public static Object getClass(Class<?extends Shape> clazz){
        Object obj = null;
        try {
            obj = Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}

使用工厂:

public class FactoryPatternDemo2 {
    public static void main(String[] args) {
        Circle circle = (Circle) ShapeFactory2.getClass(Circle.class);
        circle.draw();

        Rectangle rectangle = (Rectangle) ShapeFactory2.getClass(Rectangle.class);
        rectangle.draw();

        Square square = (Square) ShapeFactory2.getClass(Square.class);
        square.draw();

    }
}

这个版本虽然改进了频繁修改代码的缺点,但还是存在一个问题:调用后不能直接拿到想要的对象还要进行类型强转。这次我们使用泛型来解决。

升级版本二:

public class ShapeFactory3 {
    public static <T> T getClass(Class<? extends T> clazz) {
        T obj = null;

        try {
            obj = (T) Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return obj;
    }
}

使用工厂:

public class FactoryPatternDemo3 {
    public static void main(String[] args) {

        Circle circle = ShapeFactory3.getClass(Circle.class);
        circle.draw();

        Rectangle rect = ShapeFactory3.getClass(Rectangle.class);
        rect.draw();

        Shape square = ShapeFactory3.getClass(Square.class);
        square.draw();
    }
}