第二课:工厂模式 |创建型模式

145 阅读6分钟

嗨欢迎来到风筝的设计模式专栏。我相信快节奏的生活下,文字的力量依然强大!

上节课我们讲解了单例设计模式。还不清楚的家人可以先去看看之前的文章(第一课:单例模式 | 创建型模式 - 掘金 (juejin.cn)),没有看也没关系,因为我的文章尽量做到低耦合,你可以从任意文章开始你的学习之路!

今天我们来讲工厂模式。请看下文

概括

工厂模式是一种常用的面向对象设计模式,它可以用来创建复杂的对象。通俗来说,工厂模式就是将对象的创建过程和对象的使用过程分离开来,这样能够提高系统的灵活性、可扩展性和可维护性。

然而,在实际的软件开发中,不同的场景需要选择不同的设计模式来解决问题。本文将介绍三种与工厂模式密切相关的设计模式,它们分别是抽象工厂模式、简单工厂模式和工厂方法模式。这三种设计模式都是工厂模式的变体,同时也是软件开发中非常重要的设计模式之一。下面我们就逐一介绍它们的价值和用途。

一、简单工厂模式

1.1 基本概念

简单工厂模式(Simple Factory Pattern)是由一个工厂对象决定创建出哪一种产品类的实例,接口或者抽象类定义了可以被工厂创建的类的方法签名。

1.2 实现代码

首先定义一个图形接口:

public interface Shape {
    void draw();
}

实现两个实现类,圆形和矩形:

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

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

然后我们定义一个工厂类,用于获取不同图形的对象:

public class ShapeFactory {
    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();
        } 
        return null;
    }
}

在主函数中,我们可以这样用:

public class Main {
    public static void main(String[] args) {
        ShapeFactory factory = new ShapeFactory();

        // 获取 Circle 的对象,并调用它的 draw 方法
        Shape shape1 = factory.getShape("CIRCLE");
        // 调用 Circle 的 draw 方法
        shape1.draw();

        // 获取 Rectangle 的对象,并调用它的 draw 方法
        Shape shape2 = factory.getShape("RECTANGLE");
        // 调用 Rectangle 的 draw 方法
        shape2.draw();
    }
}

1.3 优缺点

简单工厂模式的优点在于我们可以根据传入的参数获取到相应的对象,而不需要知道如何创建对象的细节,从而实现了解耦。

缺点是当新增加一个产品类时,需要修改工厂类的代码,违反了 “开放封闭原则”。

二、工厂方法模式

2.1 基本概念

工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法模式让类的实例化推迟到子类中进行。

2.2 实现代码

和上一种模式一样,先定义一个 Shape 接口:

public interface Shape {
    void draw();
}

然后实现两个实现类,圆形和矩形:

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

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

定义一个工厂接口,用于创建各个图形:

public interface ShapeFactory {
    Shape getShape();
}

实现两个工厂类,分别用于创建圆形和矩形:

public class CircleFactory implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new Circle();
    }
}

public class RectangleFactory implements ShapeFactory {
    @Override
    public Shape getShape() {
        return new Rectangle();
    }
}

在主函数中,我们可以这样用:

public class Main {
    public static void main(String[] args) {
        // 获取 Circle 的工厂对象,并调用它的 getShape 方法
        ShapeFactory shapeFactory1 = new CircleFactory();
        // 获取 Circle 的对象,并调用它的 draw 方法
        Shape shape1 = shapeFactory1.getShape();
        // 调用 Circle 的 draw 方法
        shape1.draw();

        // 获取 Rectangle 的工厂对象,并调用它的 getShape 方法
        ShapeFactory shapeFactory2 = new RectangleFactory();
        // 获取 Rectangle 的对象,并调用它的 draw 方法
        Shape shape2 = shapeFactory2.getShape();
        // 调用 Rectangle 的 draw 方法
        shape2.draw();
    }
}

2.3 优缺点

工厂方法模式的优点在于它符合 “开闭原则”,即当新增加一个产品类时,只需要添加一个对应的工厂类即可。

但相对于简单工厂模式,它有一个缺点:当新增加一个工厂类时,需要额外写一个工厂类的代码。

三、抽象工厂模式

3.1 基本概念

抽象工厂模式(Abstract Factory Pattern)是指提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。

3.2 实现代码

定义两个图形接口:

public interface Shape {
    void draw();
}

public interface Color {
    void fill();
}

实现两个形状图形的实现类:

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

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

实现两个颜色的实现类:

public class Red implements Color {
    @Override
    public void fill() {
        System.out.println("Inside Red::fill() method.");
    }
}

public class Blue implements Color {
    @Override
    public void fill() {
        System.out.println("Inside Blue::fill() method.");
    }
}

定义一个抽象工厂接口,用于创建不同颜色和图形组合的对象:

public interface AbstractFactory {
    Shape getShape(String shapeType);
    Color getColor(String colorType);
}

实现两个抽象工厂类,分别用于创建不同颜色和图形组合的对象:

public class ShapeFactory implements AbstractFactory {
    @Override
    public Shape getShape(String shapeType){
        if(shapeType == null){
            return null;
        }        
        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;
    }
}

public class ColorFactory implements 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("BLUE")){
            return new Blue();
        }
        return null;
    }
}

在主函数中,我们可以这样用:

public class Main {
    public static void main(String[] args) {
        // 获取形状工厂
        AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");

        // 获取形状为 Rectangle 的对象,并调用它的 draw 方法
        Shape shape1 = shapeFactory.getShape("RECTANGLE");
        // 调用 Rectangle 的 draw 方法
        shape1.draw();

        // 获取形状为 Square 的对象,并调用它的 draw 方法
        Shape shape2 = shapeFactory.getShape("SQUARE");
        // 调用 Square 的 draw 方法
        shape2.draw();

        // 获取颜色工厂
        AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");

        // 获取颜色为 Red 的对象,并调用它的 fill 方法
        Color color1 = colorFactory.getColor("RED");
        // 调用 Red 的 fill 方法
        color1.fill();

        // 获取颜色为 Blue 的对象,并调用它的 fill 方法
        Color color2 = colorFactory.getColor("BLUE");
        // 调用 Blue 的 fill 方法
        color2.fill();
    }
}

3.3 优缺点

抽象工厂模式最大的优点在于它可以创建一组相关或者相互依赖的对象,而无需关心具体实现细节。

与之相对应的一个缺点是,当需要新增加一个产品时,需要修改所有的工厂类,从而违反了 “开放封闭原则”。

四、总结

简单工厂模式、工厂方法模式和抽象工厂模式都是针对对象创建的设计模式。简单工厂模式适用于创建单个对象,工厂方法模式适用于创建一个等级结构的对象,抽象工厂模式适用于创建多个对象的场景。

使用上述这些设计模式能够让我们更加灵活的创建对象,同时也能降低对象的耦合度。我们可以根据实际情况选择使用不同的设计模式。