设计模式之工厂模式

190 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

工厂模式是最简单也是最基础的设计模式之一,下边一起学习一下工厂模式!

一.简单工厂模式

⼜称静态工厂⽅法,可以根据参数的不同返回不同类的实例 ,专⻔定义⼀个类来负责创建其他类的实例,被创建的实例通常都具有共同的⽗类。由于⼯⼚⽅法是静态⽅法,可通过类名直接调⽤,⽽且只需要传⼊简单的参数即可。

1.核心组成

  • Factory:工厂类,简单工厂模式的核心,它负责实现 创建所有实例的内部逻辑。
  • IProduct:抽象产品类,简单工厂模式所创建的所有对象的⽗类,描述所有实例所共有的公共接⼝。
  • Product:具体产品类,是简单工厂模式的创建⽬标。

2.实现案例

2.1、创建 Product 具体产品类

public interface Car {
    void name();
}

2.2、创建 Product 具体产品类—Tesla、Byd

public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("特斯拉ModelY");
    }
}
public class Byd implements Car {
    @Override
    public void name() {
        System.out.println("比亚迪汉");
    }
}

2.3、创建Factory工厂类

public class CarFactory {
    /**
     * 根据请求参数,返回指定对象!
     *
     * @param name 名称
     * @return car
     */
    public static Car getCar(String name) {
        if ("BYD".equals(name)) {
            return new Byd();
        } else if ("特斯拉".equals(name)) {
            return new Tesla();
        } else {
            return null;
        }
    }
}

上述就是工厂设计模式——简单工程(静态工厂的一个简单使用例子),那么我们来分析下其缺点与不足之处:

简单工厂模式,实现简单,但是不满足开闭原则(扩展开放,修改关闭);
我们无法在不改动源代码的基础上实现扩展,但是实际开发比较常用 ;

比如:我们想要在工厂增加一个Dazhong(大众)类,就必须改动现有的逻辑结构,因此,引入工厂方法模式解决此问题!

二.工厂方法模式

是对简单⼯⼚模式的进⼀步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满⾜开闭原则。

  • 相⽐简单⼯⼚⽽⾔,此种⽅法具有更多的可扩展性和复⽤性,同时也增强了代码的可读性。

1.核心组成

  • IProduct:抽象产品接口,描述所有实例所共有的公共接⼝。
  • Product:具体产品类,实现抽象产品类的接⼝,⼯⼚ 类创建对象,如果有多个需要定义多个。
  • IFactory:抽象⼯⼚接口,描述具体⼯⼚的公共接⼝。
  • Factory:具体⼯⼚类,实现创建产品类对象,实现抽 象⼯⼚类的接⼝,如果有多个需要定义多个。

要实现工厂方法模式,只需要在原来的简单工厂模式基础上,做出改进,我们Tesla、Wuling两个具体产品类不变

2.实现案例

2.1、创建CarFactory抽象工厂接口

public interface CarFactory {
    Car getCar();
}

2.2、然后创建TeslaFactory 和 BydFactory 两个具体的工厂类

public class TeslaFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Tesla();
    }
}
public class BydFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Byd();
    }
}

2.3、进行测试

public class Consumer {
    public static void main(String[] args) {
        Car car = new TeslaFactory().getCar();
        Car car1 = new BydFactory().getCar();

        car.name();//特斯拉Model3
        car1.name();//比亚迪汉
    }
}

测试成功!

工厂方法模式思路如下图:

工厂方法模式优点:

  • 符合开闭原则,增加⼀个产品类,只需要实现其他具体的产品类和具体的⼯⼚类;
  • 符合单⼀职责原则,每个⼯⼚只负责⽣产对应的产品;

工厂方法模式缺点:

  • 增加⼀个产品,需要实现对应的具体⼯⼚类和具体产品类;
  • 每个产品需要有对应的具体⼯⼚和具体产品类;

三.抽象工厂模式

抽象工厂⽅法模式是简单工厂模式 和工厂方法模式的整合升级版。抽象工厂模式在 Spring 中应⽤得最为⼴泛的⼀种设计模式。

  • 工厂方法模式引⼊工厂等级结构,解决了简单工厂模式中工厂类职责过重的问题。
  • 但工厂方法模式中每个工厂只创建⼀类具体类的对象, 后续发展可能会导致工厂类过多

实现步骤

  • 1、定义两个接口:IPhoneProduct(手机)、IRouterPruduct(路由器)。
  • 2、创建具体的 手机产品 和 路由器产品。
  • 3、创建抽象工厂:IProductFactory ,其中有创建手机和创建路由器两个方法。
  • 4、创建Apple产品族(Apple工厂),实现抽象工厂IProductFactory。
  • 5、创建华为产品族(华为工厂),实现抽象工厂IProductFactory。
  • 6、创建Client去拿到工厂,获取对应的产。

接下来,我们就按照步骤实现以下抽象工厂模式 :

3.1、定义两个接口:IPhoneProduct(手机)、IRouterPruduct(路由器)

/**
 * 手机接口
 */
public interface IPhoneProduct {
    //开机
    void start();

    //关机
    void shutdown();

    //打电话
    void callUp();

    //发短息
    void sendSMS();
}
/**
 * 路由器接口
 */
public interface IRouterProduct {
    // 路由器开机
    void start();

    //  路由器关机
    void shutdown();

    // 路由器寻找wifi
    void findWifi();

    // 路由器设置
    void Setting();
}

3.2、创建具体的 手机产品 和 路由器产品

手机产品:华为手机、Apple手机

/**
 * Apple手机
 */
public class ApplePhone implements IPhoneProduct {
    @Override
    public void start() {
        System.out.println("Apple开机");
    }

    @Override
    public void shutdown() {
        System.out.println("Apple关机");
    }

    @Override
    public void callUp() {
        System.out.println("Apple打电话");
    }

    @Override
    public void sendSMS() {
        System.out.println("Apple发短信");
    }
}
/**
 * 华为手机
 */
public class HuaWeiPhone implements IPhoneProduct {
    @Override
    public void start() {
        System.out.println("华为开机");
    }

    @Override
    public void shutdown() {
        System.out.println("华为关机");
    }

    @Override
    public void callUp() {
        System.out.println("华为打电话");
    }

    @Override
    public void sendSMS() {
        System.out.println("华为发短信");
    }
}

路由器产品:Apple路由器、华为路由器

/**
 * Apple路由器产品
 */
public class AppleRouter implements IRouterProduct {
    @Override
    public void start() {
        System.out.println("Apple路由器开机");
    }

    @Override
    public void shutdown() {
        System.out.println("Apple路由器关机");
    }

    @Override
    public void findWifi() {
        System.out.println("Apple路由器找wifi");
    }

    @Override
    public void Setting() {
        System.out.println("Apple华为路由器设置");
    }
}
/**
 * 华为路由器
 */
public class HuaWeiRouter implements IRouterProduct {
    @Override
    public void start() {
        System.out.println("华为路由器开机");
    }

    @Override
    public void shutdown() {
        System.out.println("华为路由器关机");
    }

    @Override
    public void findWifi() {
        System.out.println("华为路由器找wifi");
    }

    @Override
    public void Setting() {
        System.out.println("开启华为路由器设置");
    }
}

3.3、创建抽象工厂:IProductFactory ,其中有创建手机和创建路由器两个方法

/**
 * 抽象工厂:生产工厂
 */
public interface IProductFactory {

    //生产手机
    IPhoneProduct iPhoneProduct();

    //生产路由器
    IRouterProduct iRouterProduct();
}

3.4、创建Apple产品类(Apple工厂),实现抽象工厂IProductFactory

public class AppleFactory implements IProductFactory {
    @Override
    public IPhoneProduct iPhoneProduct() {
        return new ApplePhone();
    }

    @Override
    public IRouterProduct iRouterProduct() {
        return new AppleRouter();
    }
}

3.5、创建华为产品类(华为工厂),实现抽象工厂IProductFactory

public class HuaWeiFactory implements IProductFactory {
    @Override
    public IPhoneProduct iPhoneProduct() {
        return new HuaWeiPhone();
    }

    @Override
    public IRouterProduct iRouterProduct() {
        return new HuaWeiRouter();
    }
}

3.6、创建Client去拿到工厂,获取对应的产品

public class Client {
    public static void main(String[] args) {
        System.out.println("================华为生产====================");
        HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
        IPhoneProduct product = huaWeiFactory.iPhoneProduct();
        product.start();
        product.callUp();
        product.sendSMS();

        IRouterProduct routerProduct = huaWeiFactory.iRouterProduct();
        routerProduct.findWifi();
        routerProduct.Setting();
        routerProduct.shutdown();

        System.out.println("================Apple生产====================");
        AppleFactory appleFactory = new AppleFactory();
        IPhoneProduct iPhoneProduct = appleFactory.iPhoneProduct();
        iPhoneProduct.start();
        iPhoneProduct.callUp();
        iPhoneProduct.sendSMS();

        IRouterProduct iRouterProduct = appleFactory.iRouterProduct();
        iRouterProduct.findWifi();
        iRouterProduct.Setting();
        iRouterProduct.shutdown();
    }
}

执行结果

================华为生产====================
华为开机
华为打电话
华为发短信
华为路由器找wifi
开启华为路由器设置
华为路由器关机
================Apple生产====================
Apple开机
Apple打电话
Apple发短信
Apple路由器找wifi
Apple华为路由器设置
Apple路由器关机

从上面案例可以看出,抽象工厂模式是工厂方法模式和静态工厂模式的合并,即超级工厂使用的是简单工厂模式,受超级工厂管辖的工厂使用的是工厂方法模式。 抽象工厂模式思路如下图:

四.三种工厂模式使用选择

  • 简单工厂:用来生成同一等级结构种的任意产品(不支持拓展产品)
  • 工厂方法: 用来生产同一等级结构中的固定产品(支持拓展产品)
  • 抽象工厂: 用来生产不同产品族的全部产品(支持拓展产品,支持增加产品族)
  • 简单工厂的适用场合:只有伦敦工厂(只有这一个等级),并且这个工厂只生产三种类型的pizza:chesse,pepper,greak(固定产品)。

工厂方法的适用场合:现在不光有伦敦工厂,还增设了纽约工厂(仍然是同一等级结构,但是支持了产品的拓展),这两个工厂依然只生产三种类型的pizza:chesse,pepper,greak(固定产品)。

抽象工厂的适用场合:不光增设了纽约工厂(仍然是同一等级结构,但是支持了产品的拓展),这两个工厂还增加了一种新的类型的pizza:chinese pizza(增加产品族)。

总结一下三种类型:

简单工厂就是建立一个实例化对象的类,在该类中对多个对象实例化。工厂方法模式是定义了一个创建对象的抽象方法,由子类决定要实例化的类。这样做的好处是再有新的类型的对象需要实例化只要增加子类即可。抽象工厂模式定义了一个接口用于创建对象族,而无需明确指定具体类。抽象工厂也是把对象的实例化交给了子类,即支持拓展。同时提供给客户端接口,避免了用户直接操作子类工厂。