设计模式——工厂模式

205 阅读4分钟

工厂模式

概述

工厂模式是指 在父类中定义创建对象的一个接口,由子类来决定实例化哪个类。

工厂模式分为:简单工厂模式,工厂方法模式,抽象工厂模式。

简单工厂模式

简单工厂模式是工厂模式的一种实现,它主要分为:

  • 分配任务的工厂角色;
  • 大致描述所有功能的抽象产品角色
  • 实现某一具体功能的具体产品角色

由于它每次新添加一个产品,都需要多生成if-else语句(或switch-case语句),这违背了开放-封闭原则。因此该模式使用得较少。

开放-封闭原则:强调设计的模块应该从不改变,当需求变化时(添加产品),通过添加新代码来扩展这个模块的行为,但不会去修改已存在且可工作的代码。

举例说明:我们要定义多种绘制不同形状的绘图工具。

先定义一个工具接口:

public interface Shape {
    void draw();
}

然后创建各个不同的工具:

public class Circle implements Shape {
    public Circle() {
        System.out.println("Circle");
    }
    @Override
    public void draw() {
        System.out.println("Draw Circle");
    }
}
public class Rectangle implements Shape {
    public Rectangle() {
        System.out.println("Rectangle");
    }
    @Override
    public void draw() {
        System.out.println("Draw Rectangle");
    }
}
public class Square implements Shape {
    public Square() {
        System.out.println("Square");
    }

    @Override
    public void draw() {
        System.out.println("Draw Square");
    }
}

接着创建工厂类:

public class ShapeFactory {
    // getShape方法用于根据参数shapeType来返回不同的绘图工具
    public static 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;
    }
}

最后测试一下:

public class Test {
    public static void main(String[] args) {
        Shape circle = ShapeFactory.getShape("CIRCLE");
        circle.draw();
        
        Shape rectangle = ShapeFactory.getShape("RECTANGLE");
        rectangle.draw();
    }
}

不过该实现有一个小问题:若要增加新绘图工具,就需要修改工厂类的方法。

反射机制改善简单工厂

我们可以通过反射来修改下工厂类的getShape()方法:

public class ShapeFactory {
    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 Test {
    public static void main(String[] args) {
        Circle circle = (Circle) ShapeFactory.getClass(Ano.Circle.class);
        circle.draw();

        Rectangle rectangle = (Rectangle) ShapeFactory.getClass(Ano.Rectangle.class);
        rectangle.draw();
    }
}

工厂方法模式

在该模式下每个产品都有对应的工厂。其主要角色有:

  • 抽象工厂角色
  • 具体工厂角色
  • 抽象产品角色
  • 具体产品角色

同样以绘图工具为例,在上面的基础上:首先增加一个工厂接口

public interface Factory {
    public Shape getShape();
}

增加相关工具的具体工厂类:

public class CircleFactory implements Factory {
    @Override
    public Shape getShape() {
        return new Circle();
    }
}
public class RectangleFactory implements Factory{
    @Override
    public Shape getShape() {
        return new Rectangle();
    }
}
public class SquareFactory implements Factory{
    @Override
    public Shape getShape() {
        return new Square();
    }
}

最后测试:

public class Test {
    public static void main(String[] args) {
        Factory circlefactory = new CircleFactory();
        Shape circle = circlefactory.getShape();
        circle.draw();
    }
}

工厂方法模式适用于如下场景:

(1)一个类对象不知道对应的类:我们不需要知道具体的产品类(本例中的Circle类 ),只需知道生产该产品的工厂类(本例中的CircleFactory类)即可,具体的产品由工厂负责。如本例中我们只需知道工厂接口及其绘图工厂实现类。

(2)一个类通过其子类来指定创建指定对象:抽象工厂接口只需提供创建产品的接口,然后由工厂子类来确定要创建的对象。如本例中的工厂接口通过其圆形绘图工具实现类来实现功能。

抽象工厂模式

在工厂模式中,一个工厂类仅生成一种产品。而在抽象工厂模式下,一个工厂类可以创建多组产品,一个工厂类中的多组产品通常是有关联的。

该模式下的产品角色有:

  • 抽象工厂角色
  • 具体工厂角色
  • 抽象产品角色
  • 具体产品角色

以枪械AK47,M4A1为例,两把枪使用的子弹类型分别为AK_Bullet,M4_Bullet。工厂类可分为生成枪械和对应子弹的两种工厂。

定义枪械,子弹的工厂接口:

public interface Gun {
    public void shooting();
}
public interface Bullet {
    public void load();
}

创建对应的枪,子弹具体产品类

public class AK implements Gun{
    @Override
    public void shooting() {
        System.out.println("shooting with AK");
    }
}
public class M4A1 implements Gun {
    @Override
    public void shooting() {
        System.out.println("shooting with M4A1");

    }
}
public class AK_Bullet implements Bullet {
    @Override
    public void load() {
        System.out.println("bullets with AK");
    }
}
public class M4A1_Bullet implements Bullet {
    @Override
    public void load() {
        System.out.println("Load bullets with M4A1");
    }
}

创建生成枪械,子弹的具体工厂类

public class AK_Factory implements Factory{
    @Override
    public Gun produceGun() {
        return new AK();
    }

    @Override
    public Bullet produceBullet() {
        return new AK_Bullet();
    }

}
public class M4A1_Factory implements Factory{
    @Override
    public Gun produceGun() {
        return new M4A1();
    }

    @Override
    public Bullet produceBullet() {
        return new M4A1_Bullet();
    }
}

该模式的适用场景:

(1)与工厂模式一样,不知道产品类对象对应的产品类

(2)需要多个产品完成某种功能,并且可能存在多个产品完成不同功能的情况。比如本例中一把枪的发射功能是由枪械类对象的发射方法shooting()和它所属的子弹类对象的爆炸方法load()两部分组成。

(3)系统结构稳定,不会频繁增加对象。(一旦增加就需要修改原代码,这会破坏开闭原则)。


参考资料

JavaGuide