设计模式-工厂模式

简介: 设计模式-工厂模式

工厂模式介绍

工厂模式定义

工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

看下 GOF为工厂模式的定义:

“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”(在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。)

工厂模式分类

  • 简单工厂模式 (Simple Factory),又称静态工厂方法模式 (Static Factory Method Pattern)。
  • 工厂方法模式(Factory Method)。
  • 抽象工厂模式(Abstract Factory)。

使用场景

  1. 生产一个发送消息的 产品对象,比如通过邮件、短信、微信公众号等产品发送消息给用户。
  2. Spring 中 FactoryBean 的 getObject();spring 中 各种各样的 bean。就可以通过工厂模式创建并且实现了依赖解耦。

工厂模式的优点

  • 解耦:把对象的创建和使用分开。
  • 降低代码复杂度:如果某个对象的创建比较复杂,或者其过程比较多的步骤。多个地方都会使用就会产生很多重复代码
  • 降低维护成本:创建过程有工厂统一管理,当业务发生变化,不需要去找代码中创建对象 A 的地方组个修改,只要在工厂里面修改即可。开闭原则。

简单工厂模式

其实这个并不算设计模式,适合创建简单对象,创建的对象较少。客户端不关心对象的创建过程。

简单工厂模式角色

  • 工厂角色(Factory):简单工厂模式的核心,负责创建所有实例的内部逻辑,提供外部使用创建所需要的产品。
  • 抽象产品角色(Product):简单工厂所创建的类型。
  • 具体产品(Concrete Product)角色:简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

简单工厂代码实现

创建发送器接口,也就是产品角色

public interface Sender {
  /**
   * 发送信息
   * @param to 收件人
   * @param msg 消息
   * @return
   */
  boolean send(String to, String msg);
}

创建具体产品,分别是邮件发送器、短信发送器。

public class MailSender implements Sender {
  @Override
  public boolean send(String to, String msg) {
    System.out.println("MailSender:收件人:" + to + ",消息为:" + msg);
    return true;
  }
}
public class SmsSender implements SenderService {
  @Override
  public boolean send(String to, String msg) {
    System.out.println("SmsSender:收件人:" + to + ",消息为:" + msg);
    return true;
  }
}

创建简单工厂

/**
 * 工厂类,创建实例对象。缺点当字符串输错则得不到对象
 * @author unique
 *
 */
public class SendFactory {
  public Sender getObject(String type) {
    Sender sender = null;
    switch (type) {
    case "mail":
      senderService = new MailSender();
      break;
    case "sms":
      senderService = new SmsSender();
      break;
    default:
      System.out.println("请输入正确类型");
      break;
    }
    return sender;
  }
}

单元测试

public class SimpleFactoryTest {
  public static void main(String[] args) {
    SendFactory factory = new SendFactory();
    Sender sender = factory.getObject("mail");
    sender.send("大兄弟", "你是最棒的!");
  }
}

缺点

当我们新增产品类的时候,就需要修改工厂类中的 getObject() 方法,不符合 开放-封闭原则。

工厂方法模式

工厂模式中使用最多的一种。

与简单公差个模式最大的区别就是我们不再提供一个统一的工厂来创建所有的产品,二十针对不同的产品提供不同的工厂。也就是每个产品都有一个与之对应的工厂。

适用场景

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏原则。
  • 创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

工厂方法模式角色

  • 抽象工厂(Abstract Factory)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
  • 具体工厂(Concrete Factory)角色 :这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
  • 抽象产品(AbstractProduct)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品(Concrete Product)角色 :这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应

代码示例

基于上面的简单工厂,我们改造下。新建一个抽象工厂角色

public interface SenderFactory {
  /**
   * 生成对象
   * @return
   */
  public Sender getObject();
}

增加短信、邮件工厂类,实现抽象工厂接口。

public class SendMailFactory implements SenderFactory {
  @Override
  public Sender getObject() {
    return new MailSender();
  }
}
public class SendSmsFactory implements SenderFactory {
  @Override
  public Sender getObject() {
    return new SmsSenderServiceImpl();
  }
}

测试代码

public class Test {
  public static void main(String[] args) {
    SenderFactory senderFactory = new SendMailFactory();
    Sender sender = senderFactory.getObject();
    sender.send("大兄弟", "你是最棒的!");
  }
}

抽象工厂模式

在工厂方法模式中,其实我们有一个潜在意识的意识。那就是我们生产的都是同一类产品。抽象工厂模式是工厂方法的仅一步深化,在这个模式中的工厂类不单单可以创建一种产品,而是可以创建一组产品。这个产品会依赖多个合成一个。比如我们的电脑厂商 有因特尔和AMD 生产的主板与CPU。这个产品族有CPU跟主板。

抽象工厂模式和工厂方法模式一样,都符合开放-封闭原则。但是不同的是,工厂方法模式在增加一个具体产品的时候,都要增加对应的工厂。但是抽象工厂模式只有在新增一个类型的具体产品时才需要新增工厂。也就是说,工厂方法模式的一个工厂只能创建一个具体产品。而抽象工厂模式的一个工厂可以创建属于一类类型的多种具体产品。工厂创建产品的个数介于简单工厂模式和工厂方法模式之间。

适用场景

  • 和工厂方法一样客户端不需要知道它所创建的对象的类。
  • 需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品)
  • 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)

抽象工厂方法模式的角色与工厂方法模式一致

我们的电脑有主板、CPU、内存…组成。这些都是产品,现在提供一个工厂,直接同时生产出 CPU与对应的主板,避免单独去创建。也就是所谓的一套,一个系列。

比如 有因特尔工厂出品的 CPU 与 主板,AMD 工厂出品的 CPU 与主板。

代码示例

定义CPU 与主板两个产品

public interface CPU {
    void calculate();
}
public interface Mainboard {
    void installCPU();
}

以及产品的具体实现,比如 AMD 公司出品的、因特尔公司出品的 CPU 与主板

public class AmdCpu implements CPU {
    /**
     * CPU的针脚数
     */
    private int pins = 0;
    public AmdCpu(int pins) {
        this.pins = pins;
    }
    @Override
    public void calculate() {
        System.out.println("AMD CPU的针脚数:" + pins);
    }
}
public class IntelCPU implements CPU {
    /**
     * CPU的针脚数
     */
    private int pins = 0;
    public IntelCPU(int pins) {
        this.pins = pins;
    }
    @Override
    public void calculate() {
        System.out.println("Intel CPU的针脚数:" + pins);
    }
}
public class AmdMainboard implements Mainboard {
    /**
     * CPU插槽的孔数
     */
    private int cpuHoles = 0;
    /**
     * 构造方法,传入CPU插槽的孔数
     *
     * @param cpuHoles
     */
    public AmdMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }
    @Override
    public void installCPU() {
        // TODO Auto-generated method stub
        System.out.println("AMD主板的CPU插槽孔数是:" + cpuHoles);
    }
}
public class IntelMainboard implements Mainboard {
    /**
     * CPU插槽的孔数
     */
    private int cpuHoles = 0;
    /**
     * 构造方法,传入CPU插槽的孔数
     *
     * @param cpuHoles
     */
    public IntelMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }
    @Override
    public void installCPU() {
        System.out.println("Intel主板的CPU插槽孔数是:" + cpuHoles);
    }
}

接着我们先创建一个抽象工厂角色,能生产 CPU 与主板系列产品的工厂方法定义。

public interface MainboardCPUFactory {
    /**
     * 创建CPU对象
     *
     * @return CPU对象
     */
    public CPU createCpu();
    /**
     * 创建主板对象
     *
     * @return 主板对象
     */
    public Mainboard createMainboard();
}

因特尔工厂定义

public class IntelFactory implements MainboardCPUFactory {
    @Override
    public CPU createCpu() {
        return new IntelCPU(755);
    }
    @Override
    public Mainboard createMainboard() {
        return new IntelMainboard(755);
    }
}

AMD 工厂

public class AmdFactory implements MainboardCPUFactory {
    @Override
    public CPU createCpu() {
        return new AmdCpu(938);
    }
    @Override
    public Mainboard createMainboard() {
        return new AmdMainboard(938);
    }
}

最后我们来测试

public class AbstactFactoryTest {
    public static void main(String[] args) {
        //使用因特尔工厂生产
        MainboardCPUFactory intelFactory = new IntelFactory();
        CPU cpu = intelFactory.createCpu();
        Mainboard mainboard = intelFactory.createMainboard();
        mainboard.installCPU();
        cpu.calculate();
    }
}

打印

Intel主板的CPU插槽孔数是:755
Intel CPU的针脚数:755


相关文章
|
6月前
|
设计模式
设计模式【二】:工厂模式
设计模式【二】:工厂模式
45 0
|
设计模式 Java
设计模式~工厂模式-03
工厂模式 简单工厂模式 优点: 缺点: 工厂方法模式
53 0
|
设计模式 Java C++
设计模式之工厂模式详解和应用
设计模式之工厂模式详解和应用
65 0
|
5月前
|
设计模式 数据格式 XML
设计模式-工厂模式-1-1
【6月更文挑战第10天】本文介绍了工厂模式的两种主要类型:简单工厂和工厂方法。简单工厂模式通过工厂类动态创建对象,例如根据配置文件后缀选择不同解析器。为提高可读性和复用性,可将创建逻辑封装到独立类中。当需添加新解析器时,可能涉及对工厂类的修改,但这在偶尔调整时可接受。工厂方法模式则通过多态消除if分支,增加扩展性,更符合开闭原则。当需要新增解析器时,只需创建实现特定接口的新工厂类。
30 2
设计模式-工厂模式-1-1
|
5月前
|
设计模式 XML 缓存
设计模式-工厂模式-1-2
【6月更文挑战第11天】工厂模式用于封装对象创建,但当load函数与工厂类耦合时,问题出现。为解决此问题,引入了工厂的工厂,如`RuleConfigParserFactoryMap`,它创建并缓存工厂对象,简化了代码修改。然而,过多的Factory类会增加复杂性,简单工厂模式在此类应用中更为适用。当对象创建逻辑复杂,需组装其他对象或避免if-else时,采用工厂方法模式。抽象工厂则处理多维度分类的对象创建。总结:工厂模式的核心价值在于封装变化、代码复用、隔离复杂性和控制复杂度,适用于创建逻辑复杂的情况,否则直接使用new操作即可。
27 5
|
6月前
|
设计模式 消息中间件 Java
设计模式之工厂模式(C++)
设计模式之工厂模式(C++)
78 0
|
6月前
|
设计模式 前端开发 API
【设计模式】之工厂模式
工厂模式是一种常用的创建对象的设计模式,它通过封装对象的创建逻辑,提供统一的接口,实现了代码的解耦和可扩展性。在实际开发中,可以根据具体需求选择是否使用工厂模式来创建对象。工厂模式可以应用于任何需要创建对象的场景。通过使用工厂模式,我们可以提高代码的可维护性、可扩展性和可测试性,使得代码更加灵活和易于理解。
75 0
|
设计模式 Java C#
设计模式之工厂模式(2)
接着,我们定义一个抽象工厂类AbstractFactory,它有两个抽象方法createShape和createColor,分别返回一个Shape对象和一个Color对象: java
51 0
|
设计模式 前端开发 Java
设计模式之工厂模式(1)
工厂模式是一种对象创建型模式,它提供了一种创建对象的最佳实践。在工厂模式中,我们在创建对象时不使用 new 关键字,而是通过调用工厂方法来创建对象。工厂方法是一种在子类中定义的方法,该方法负责实例化对象。工厂方法可以返回不同的对象类型,因此工厂模式可以创建一组相关或不相关的对象。这样就可以将对象的创建和使用解耦。
60 0
|
设计模式 消息中间件 Java
一起来学设计模式之工厂模式
前言 目前正在出一个设计模式专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~ 本节给大家讲一下设计模式中的工厂模式~ 本专题的所有案例代码主要以Java语言为主, 好了, 废话不多说直接开整吧~ 工厂模式 工厂模式是一种常用的设计模式,它提供了一种创建对象的方式,该方式隐藏了对象创建的细节并提供了一个通用的接口,从而使得代码更加灵活和可扩展。在工厂模式中,我们将对象的创建过程封装到一个工厂类中,通过工厂类来创建具体的对象,这样客户端就不需要关心对象的创建过程,只需要调用工厂类提供的接口来获取所需的对象即可。