Java设计模式 —— 【创建型模式】工厂模式(简单工厂、工厂方法模式、抽象工厂)详解

文章目录


前言

先看个案例:【手机和手机店】在没有工厂的时候,手机店需要手机就需要自己创建,还得根据用户的选择进行创建不同的手机,如下图:

这样手机店直接与手机对象接触,就会对该对象耦合严重,假如我们添加新的手机品牌,还得修改手机店的create方法,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,将对象的创建封装在工厂内,实现使用者和对象解耦;所以说,工厂模式最大的优点就是:解耦

工厂模式的主要目的是将对象的创建过程封装在工厂类中,客户端代码只需要关心从工厂获取对象的过程,而不需要了解对象的创建细节。这样可以降低代码的耦合度,提高代码的可维护性和可扩展性


一、简单工厂(静态工厂)

1、概述

简单工厂不是一种设计模式,反而比较像是一种编程习惯。把对象的创建和业务逻辑层分开,实现使用方(手机店)与对象(手机)的解耦。但工厂和产品之间还是存在耦合关系。

主要包含以下角色:

  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品: 实现或者继承抽象产品的子类
  • 具体工厂: 提供了创建产品的方法,调用者通过该方法来获取产品。

2、代码实现

抽象手机类【抽象产品】:

java 复制代码
public abstract class Phone {
    public abstract String getName();
}

手机产品【具体产品】:

java 复制代码
public class  HuaWei extends Phone {
    @Override
    public String getName() {
        return "华为手机";
    }
}

public class XiaoMi extends Phone {
    @Override
    public String getName() {
        return "小米手机";
    }
}

手机工厂【具体工厂】:

java 复制代码
public class Factory {
    public static Phone createPhone(String name) {
        Phone phone = null;
        if("小米".equals(name)) {
            phone = new XiaoMi();
        } else if("华为".equals(name)) {
            phone = new HuaWei();
        }
        return phone;
    }
}

手机店【使用者】:

java 复制代码
public class Sotre {
    public static Phone orderPhone(String name) {
        return Factory.createPhone(name);
    }
}

测试:

java 复制代码
public class Test {
    public static void main(String[] args) {
        Phone xiaomi = Sotre.orderPhone("小米");
        System.out.println(xiaomi.getName());
        Phone huawei = Sotre.orderPhone("华为");
        System.out.println(huawei.getName());
    }
}

3、优缺点

优点:

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

缺点:

增加新产品时还是需要修改工厂类的代码,违背了"开闭原则"。


二、工厂方法模式

1、概述

在在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体的工作交给子类去做。 定义一个用于创建对象的接口(抽象工厂),让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。很好的解决了简单工厂的问题,遵循开闭原则。

工厂方法模式的主要角色:

  • 抽象工厂: 提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂: 主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

2、代码实现

抽象手机类【抽象产品】:

java 复制代码
public abstract class Phone {
    public abstract String getName();
}

手机产品【具体产品】:

java 复制代码
//小米手机
public class XiaoMi extends Phone {
    @Override
    public String getName() {
        return "小米手机";
    }
}

//华为手机
public class HuaWei extends Phone {
    @Override
    public String getName() {
        return "华为手机";
    }
}

抽象工厂:

java 复制代码
class interface PhoneFactory {
    Phone createPhone();
}

具体工厂:

java 复制代码
//小米工厂
public class XiaoMiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new XiaoMi();
    }
}

//华为工厂
public class HuaWeiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new HuaWei();
    }
}

手机店【使用者】:

java 复制代码
public class Store {
    public Phone orderPhone(PhoneFactory factory) {
        return factory.createPhone();
    }
}

测试:

java 复制代码
public class Test {
    public static void main(String[] args) {
        Store store = new Store();
        Phone huaWei = store.orderPhone(new HuaWeiFactory());
        Phone xiaomi = store.orderPhone(new XiaoMiFactory());

        System.out.println(xiaomi.getName());
        System.out.println(huaWei.getName());
    }
}

3、优缺点

优点:

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

缺点:

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

三、抽象工厂模式

1、概述

抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产同一个等级的产品(小米手机,华为手机),而抽象工厂模式可生产多个等级的产品(小米家族,华为家族)。

抽象工厂模式的主要角色如下:

  • 抽象工厂: 提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品(小米工厂 和华为工厂的所有功能的抽象【创建手机,创建路由器】)。
  • 具体工厂: 主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建(小米工厂造小米家族产品,华为工厂造华为家族产品)。
  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品(小米和华为所拥有的同一系列产品的抽象【手机产品,路由器产品】)。
  • 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

2、代码实现

抽象工厂:

java 复制代码
public interface Factory {
    // 生产手机
    Phone createPhone();
    // 生产路由器
    Router createRouter();
}

具体工厂:

java 复制代码
//小米工厂
public class XiaoMiFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new XiaoMiPhone();
    }
    @Override
    public Router createRouter() {
        return new XiaoMiRouter();
    }
}

//华为工厂
public class HuaWeiFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new HuaWeiPhone();
    }
    @Override
    public Router createRouter() {
        return new HuaWeiRouter();
    }
}

抽象产品:

java 复制代码
//手机产品
public abstract class Phone {
    public abstract String getName();
}

//路由器类
public abstract class Router {
    public abstract String getName();
}

具体产品:

java 复制代码
public class XiaoMiPhone extends Phone{
    @Override
    public String getName() {
        return "小米手机";
    }
}

public class HuaWeiPhone extends Phone {
    @Override
    public String getName() {
        return "华为手机";
    }
}
java 复制代码
public class XiaoMiRouter extends Router {
    @Override
    public String getName() {
        return "小米路由器";
    }
}

public class HuaWeiRouter extends Router {
    @Override
    public String getName() {
        return "华为路由器";
    }
}

手机店:

java 复制代码
public class Store {
    private Factory factory;
    public void setFactory(Factory factory) {
        this.factory = factory;
    }
    public Phone orderPhone(){
         return factory.createPhone();
    }
    public Router orderRouter(){
        return factory.createRouter();
    }
}

测试:

java 复制代码
public class Test {
    public static void main(String[] args) {
        Store store = new Store();
        store.setFactory(new XiaoMiFactory());
        Phone xiaomiPhone = store.orderPhone();
        Router xiaomiRouter = store.orderRouter();
        System.out.println(xiaomiPhone.getName());
        System.out.println(xiaomiRouter.getName());
        System.out.println("===========");
        store.setFactory(new HuaWeiFactory());
        Phone huaweiPhone = store.orderPhone();
        Router huaweiRouter = store.orderRouter();
        System.out.println(huaweiPhone.getName());
        System.out.println(huaweiRouter.getName());
    }
}

如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类。

3、优缺点

优点:

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:

当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。


四、总结

  1. 以上述案例为例,没有工厂就是手机店直接造手机,使用者和对象高度耦合,新增品类时违背开闭原则,一个手机店造不同手机违背单一职责原则;
  2. 由此引出简单工厂,手机店只需要和工厂打交道,售卖手机,不负责造手机的过程,实现手机店和对象的解耦,但是工厂和对象还是存在上述问题;
  3. 由此工厂在向上抽象出"工厂规范",形成工厂方法模式,不同的工厂负责不同的职责,添加新的品类时增加对应工厂和产品即可;
  4. 在往下走,工厂做大做强以后,不只是可以生产手机,还添加了新的产品路由器,形成抽象工厂模式。
  5. 工厂方法模式是针对单一的品类进行的实现,二抽象工厂是针对多个品类(产品族)的实现。
相关推荐
Coder个人博客13 小时前
Linux6.19-ARM64 mm mmu子模块深入分析
大数据·linux·车载系统·系统架构·系统安全·鸿蒙系统
侠客行031714 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪14 小时前
深入浅出LangChain4J
java·langchain·llm
灰子学技术15 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
老毛肚15 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎16 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
二十雨辰16 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码16 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚16 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂16 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言