工厂模式-23种设计模式系列

什么是工厂模式?

定义: 工厂模式又称为创建模式,它是建对象的一种最佳方式。工厂模式的本质就是用工厂方法代替new操作创建一种实例化对象的方式。一句话中总结就是方便创建 同种类型接口产品 的 复杂对象

核心:

  • 实现了创建者和调用者分离
  • 实例对象不用new,而用工厂方法代替
  • 将选择实现类,创建对象统一管理和控制。从而将调用者和我们的实现类解耦

三种模式:

  • 简单工厂模式:用来生产同一等级结构的任意商品(对于增加新的商品,需要修改已有代码)
  • 工厂方法模式:用来生产同一等级结构中固定商品(支持增加任意产品)
  • 抽象工厂模式:围绕一个超级工厂创建其他工厂,该超级工厂又城其他工厂的工厂。

应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。

注意事项: 作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

简单工厂模式

在介绍简单工程模式前,我们现需要回顾一下OOP的七大原则,因为工厂模式也是需要符合这七大原则的。

OOP七大原则:

  • 开闭原则:一个软件的实体应该对扩展开放,对修改关闭
  • 依赖倒转原则:要针对接口编程,不要针对实现编程
  • 迪米特法则:直与你直接的朋友通信,避免和陌生人通信

然后我们写一个车的接口

public interface Car {
    void Name();
}

再写两个车的实现类

public class Wuling implements Car{
    @Override
    public void Name() {
        System.out.println("五菱宏光!");
    }
}
public class TesLa implements Car{
    @Override
    public void Name() {
        System.out.println("特斯拉!");
    }
}

再过去我们想要得到Wuling和Tesla的对象,最常用的方法就是直接new。

//消费者(测试类)
public class Consumer {
    public static void main(String[] args) {
        Car car1=new Wuling();
        Car car2=new TesLa();

        car1.Name();car2.Name();
    }
}

在这里插入图片描述
但是上面这种操作,我们需要知道接口和所有的实现类才能得到对象。就好像你想要一台车,然后你自己造(new)了一辆车,但是现实生活中,如果你想要的一台车,你会怎么做?去工厂买,你不需要知道工厂怎么造车。

工厂模式的核心就是实例对象不用new,而用工厂方法代替,我们用代码实现一个车工厂

public class CarFactory {
    public static Car getCar(String car){
        if (car.equals("五菱宏光"))
            return new Wuling();
        else if (car.equals("特斯拉"))
            return new TesLa();
        else
            return null;
    }
}

这样我们的消费者需要车,直接去工厂买就可以了,不需要自己造了。需要什么车(Car),直接给车工厂(CarFactory)传一个字符串参数就可以了,不需要知道里面的细节,甚至不需要知道实现类(符合OOP七大原则之依赖倒转原则:要针对接口编程,不要针对实现编程)。

//用工厂实现
Car car1 = CarFactory.getCar("五菱宏光");
Car car2 = CarFactory.getCar("特斯拉");

在这里插入图片描述

问题来了,如果我们需要增加一个实现类呢?

public class DaZhong implements Car{
    @Override
    public void Name() {
        System.out.println("大众!");
    }
}

我们需要修改我们的车工厂(CarFactory),在里面加一个判断

public class CarFactory {
    public static Car getCar(String car){
        if (car.equals("五菱宏光"))
            return new Wuling();
        else if (car.equals("特斯拉"))
            return new TesLa();
        else if (car.equals("大众"))
            return new DaZhong();
        else
            return null;
    }
}

这样就违反了OOP七大原则(开闭原则:一个软件的实体应该对扩展开放,对修改关闭),所以简单工厂模式是有一点小问题的,不能动态的增加实现类,无法在不修改车工厂代码的前提下增加实现类,而且简单工厂里面车工厂的方法都是静态的,因此简单工厂模式又叫静态工厂模式

但是事实上,看源码可知,我们使用的最多的还是简单工厂模式,因为如果想做满足开闭原则,你将会付出很大代价,代码量将会增大很多,就比如下面的 工厂方法模式

工厂方法模式

工厂方法模式是思路很简单,就是再写一个车工厂的接口。

public interface CarFactory {
    Car getCar();
}

让每个车有自己的工厂,每个工厂再实现车工厂的接口。

//五菱车工厂
public class WulingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Wuling();
    }
}
//特斯拉车工厂
public class TeslaFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new TesLa();
    }
}

消费者如果想要车,只需去对应的车工厂去买车就可以了。要五菱去五菱车工厂,要特斯拉去特斯拉车工厂。

Car car1 = new WulingFactory().getCar();
Car car2 = new TeslaFactory().getCar();

在这里插入图片描述

这样的话,即使再增加实现类,也只需要继承车工厂的接口写一个实现类即可,不需要修改车工厂的代码了。和简单工厂模式相比,简单工厂模式只有一个车工厂类,所有的车都是在那里面生成。工厂方法模式有多个车工厂,每个车都有自己的车工厂,但是所有的车工厂又都实现车工厂的接口,可以实现动态的增加车的实现类。

比如我们增加一个摩拜单车

public class Mobai implements Car{
    @Override
    public void Name() {
        System.out.println("摩拜单车!");
    }
}

只需要增加摩拜单车的车工厂,完全不需要改动其他类的代码。

public class MobaiFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Mobai();
    }
}

消费者想要摩拜只需要去摩拜车工厂去买即可。

Car car3 = new MobaiFactory().getCar();

在这里插入图片描述

既然工厂方法模式可以动态的增加实现类还符合开闭原则,那为什么在源码中简单工程模式使用的更多呢?
在这里插入图片描述

简单工厂模式和工厂方法模式进行对比

  • 结构复杂度上,simple(简单工厂模式)更简单
  • 代码复杂度上,simple(简单工厂模式)更简单
  • 编程复杂度上,simple(简单工厂模式)更简单
  • 管理复杂度上,simple(简单工厂模式)更简单

所以根据设计原则我们应该选择工厂方法模式,但是在实际开发中,简单工程模式使用更多。(当然不是想偷懒)

抽象工厂模式

抽象工厂模式提供了一个 创建一系列相关或相互依赖对象的接口,无需指定他们具体的类。

在介绍抽象工厂之前,我们需要先清除一个概念,产品族和产品等级。就拿小米和华为两家公司生产的手机和路由器来举例:小米手机和小米路由器都是小米的产品,属于同一个产品族,而小米手机和华为手机都是手机,属于同一个产品等级。
在这里插入图片描述

我们先定义手机和路由器的接口

//手机产品接口
public interface IphoneProduct {
    void start();//开机
    void shutdown();//关机
    void callup();//打电话
    void sendSMS();//发信息
}
//路由器产品接口
public interface IRouterProduct {
    void start();//开机
    void shutdown();//关机
    void openWifi();//打开WiFi
    void setting();//设置
}

因为小米和华为都有自己的手机和路由器,所以需要分别实现他们的实现类。

//小米手机
public class XiaomiIphone 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("用小米手机发信息");
    }
}
//华为手机
public class HuaweiIphone 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("用华为手机发信息");
    }
}
//小米路由器
public class XiaomiIRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("开启小米路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭小米路由器");
    }

    @Override
    public void openWifi() {
        System.out.println("打开小米WiFi");
    }

    @Override
    public void setting() {
        System.out.println("打开小米设置");
    }
}
//华为路由器
public class HuaweiIRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("开启华为路由器");
    }

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

    @Override
    public void openWifi() {
        System.out.println("打开华为WiFi");
    }

    @Override
    public void setting() {
        System.out.println("打开华为设置");
    }
}

现在产品都已经有了,我们需要去写制造他们的工厂,小米工厂和华为工厂。无论是小米还是华为,工厂都是要生产手机和路由器的,所以我们可以先写一个抽象工厂接口,小米和华为都去继承这个抽象工厂,不过小米生产小米的手机和路由器,华为生产华为的手机和路由器。

//抽象工厂
public interface IProductFactory {
    //生产手机
    IphoneProduct iphoneproduct();

    //生产路由器
    IRouterProduct irouterproduct();
}
//华为工厂
public class HuaweiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneproduct() {
        return new HuaweiIphone();//生产华为手机
    }

    @Override
    public IRouterProduct irouterproduct() {
        return new HuaweiIRouter();//生产华为路由器
    }
}
//小米工厂
public class XiaomiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneproduct() {
        return new XiaomiIphone();//生产小米手机
    }

    @Override
    public IRouterProduct irouterproduct() {
        return new XiaomiIRouter();//生产小米路由器
    }
}

做完这些后,我们如果想要小米的产品就去小米工厂制造,如果想要华为的产品就去华为工厂制造。

 public static void main(String[] args) {
        System.out.println("======================小米系列产品======================");
        XiaomiFactory xiaomiFactory = new XiaomiFactory();
        IphoneProduct Xiaomiiphone = xiaomiFactory.iphoneproduct();
        IRouterProduct Xiaomiirouter = xiaomiFactory.irouterproduct();
        Xiaomiiphone.callup();Xiaomiirouter.openWifi();

        System.out.println("======================华为系列产品======================");
        HuaweiFactory huaweiFactory = new HuaweiFactory();
        IphoneProduct Huaweiiphone = huaweiFactory.iphoneproduct();
        IRouterProduct Huaweiirouter = huaweiFactory.irouterproduct();
        Huaweiiphone.callup();Huaweiirouter.openWifi();
    }

在这里插入图片描述

最后的所有类的结构图就是这个样子,IProductFactory就是抽象工厂,围绕着抽象工厂建造其他工厂,所以抽象工厂又称为工厂的工厂。
在这里插入图片描述

如果华为和小米的产品族里面还有笔记本,那我们就需要添加一个产品接口,再修改抽象工厂和实现的类,加入笔记本的制造方法。这样就违反OOP的开闭原则(一个软件的实体应该对扩展开放,对修改关闭),但是如果我们的产品是长期稳定不变的,就可以接受。和前两种工厂 模式相比,抽象工厂把同一产品族放到了一起,一个工厂可以生产一个产品族。

总结

简单工厂模式虽然违反了OOP七大原则,但是在实际中还是使用最多的。

工厂方法模式通过增加工厂在不违反OOP开闭原则的前提下实现动态扩展,但是代码量大,编程和管理复杂反而没有简单工厂使用多。

抽象工厂模式围绕一个抽象工厂去创建其他工厂,一个工厂可以生产一个产品族而不只是一个产品,但是不适合产品经常变动的情况。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章