设计模式-工厂模式

简介: 工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。

工厂模式定义


工厂方法(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. 生产一个发送消息的 产品对象,比如通过邮件、短信、微信公众号等产品发送消息给用户。


  1. 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();
    }
}
相关文章
|
数据挖掘
跟着 Nature 学作图 | 相关性热图(显示相关性散点图)
跟着 Nature 学作图 | 相关性热图(显示相关性散点图)
786 0
|
8月前
|
存储 弹性计算 调度
基于Knative的LLM推理场景弹性伸缩方案
Knative的基于请求弹性配置与大语言模型(LLM)的推理场景高度契合。此外,它的资源降配特性可以显著帮助用户降低成本。本文详细介绍基于 Knative 的 LLM 推理场景弹性伸缩方案。
|
6月前
|
XML Java 数据库连接
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
199 21
|
6月前
|
搜索推荐 API 开发者
京东商品详情优惠券API接口全攻略
京东商品详情优惠券API接口为电商开发者和商家提供了精准查询、获取详细信息及实时监测优惠券状态的功能。通过商品ID,可筛选出特定商品的定向或店铺通用优惠券,获取面额、使用门槛、领取条件等详尽信息,并监测优惠券的领取情况。该接口支持多种筛选参数,满足个性化需求,助力电商业务拓展与创新。示例代码展示了如何使用Python调用此接口,实现优惠券信息的高效获取。
529 23
|
7月前
|
安全 网络安全 数据安全/隐私保护
HTTPS与SSL证书的关系
**HTTPS 与 SSL 证书:安全通信的基石** 在互联网时代,网络安全至关重要。HTTPS 和 SSL 证书是保障网站安全通信的关键。HTTPS 是 HTTP 的安全版本,通过 SSL/TLS 协议加密数据,防止窃取和篡改。SSL 证书用于验证网站身份并加密通信,包含域名、CA、公钥等信息。两者共同确保数据加密、身份验证,提升用户信任度,并有助于 SEO 优化。部署 HTTPS 和 SSL 证书是提升网站安全性和用户体验的必要措施。
|
10月前
|
机器学习/深度学习 监控 安全
量化合约对冲策略交易app系统开发技术规则
量化合约对冲策略交易APP系统开发技术规则涵盖系统架构设计、量化策略实现、交易管理、风险管理、用户界面设计及性能优化等方面。通过模块化设计、分布式架构、数据持久化、策略开发、算法交易、回测优化、订单管理、持仓监控、资金安全、风险控制、实时监控、安全审计、界面设计、反馈机制、多语言支持、响应速度、资源优化和兼容性等措施,确保系统的稳定、安全、高效和易用。
|
存储 Java 程序员
【C语言入门】C语言入门:探索编程世界的基础概念
【C语言入门】C语言入门:探索编程世界的基础概念
270 2
|
监控 安全 网络安全
局域网管理监控的远程访问控制:利用SSH和Python实现安全管理
在当今数字化时代,局域网管理监控对于确保网络安全至关重要。远程访问控制是一项关键任务,通过利用SSH(Secure Shell)和Python编程语言,我们可以实现更加安全的管理方法。本文将介绍如何使用这两者结合,为局域网管理提供可靠的远程访问控制。
411 1
|
算法 数据可视化 网络可视化
R语言Apriori算法关联规则对中药用药复方配伍规律药方挖掘可视化(上)
R语言Apriori算法关联规则对中药用药复方配伍规律药方挖掘可视化
R语言Apriori算法关联规则对中药用药复方配伍规律药方挖掘可视化(上)
|
安全
如何设置Burpsuite中的代理,及安装安全证书
如何设置Burpsuite中的代理,及安装安全证书
253 0

热门文章

最新文章