Java设计模式之工厂设计模式

简介

工厂模式是一种常见的设计模式,用于创建对象的过程中,通过工厂类来封装对象的创建过程。其核心思想是将对象的创建和使用分离,从而降低耦合度,提高代码的可维护性和可扩展性。工厂模式通常包括三种类型:简单工厂工厂方法抽象工厂

工厂模式与其他设计模式的主要区别在于,它是一种创建型模式,用于创建对象的过程中,通过工厂类来封装对象的创建过程。与之类似的还有单例模式、建造者模式等。工厂模式主要用于以下两个方面:

  1.     对象的创建和使用分离:将对象的创建过程封装到工厂类中,避免了客户端直接依赖具体的产品类,从而提高了代码的可维护性和可扩展性。
  2.     创建多个产品族或产品等级结构:当需要创建多个产品族或产品等级结构时,工厂模式可以提供一个统一的接口,方便客户端进行调用。
     

什么是简单工厂模式?

简单工厂模式也叫静态工厂模式,属于类的创建型模式。提供一个创建对象实例的功能,而无须关心其具体实现。被创建实例的类型可以是接口、抽象类,也可以是具体的类。 

简单工厂模式的本质:选择实现 。

设计意图: 通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

简单工厂模式的结构

简单工厂模式涉及的角色及其职责如下:

  • 工厂(Factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑,该类可以被外界直接调用,创建所需的产品对象。
  • 抽象(Product)角色:简单工厂模式所创建的所有对象的父类,它负责约定所有具体产品类所共有的公共接口。
  • 具体产品(ConcreteProduct)角色:简单工厂模式所创建的真正实例对象。

以具体代码为例: 

现在有两种水果:苹果(Apple)和香蕉(Banana),为了演示,为这两种水果添加一个采集get()方法。 

public class Apple{
    /*
     * 采集
     */
     public void get(){
        System.out.println("采集苹果");
    }
}
public class Banana{
    /*
     * 采集
     */
    public void get(){
        System.out.println("采集香蕉");
    }
}

如果要采集水果,在不使用任何设计模式的情况下,我们一般都会这样做。

public class Client {
    public static void main(String[] args){
 
        //实例化一个Apple
        Apple apple = newApple();
        //实例化一个Banana
        Banana banana = newBanana();
        apple.get();
        banana.get();
    }
}

客户端分别创建苹果和香蕉两个具体产品的实例并调用其采集的方法,这样做存在的问题是:客户端需要知道所有的具体水果种类,即客户端与所有的水果类都存在了耦合关系,不符合面向对象设计中的“低耦合”原则。

以上问题如何解决呢?答案:使用简单工厂,利用接口进行“封装隔离”。 

Apple和Banana类既然都是水果,且共有一个采集的get()方法,我们可以为其添加一个父类或让其实现一个共同的接口。在此,我们添加一个Fruit接口。  

public interface Fruit {
    /*
     * 采集
     */
    public void get();
}

让Apple和Banana类都实现Fruit接口。

public class Apple implements Fruit{
    /*
     * 采集
     */
     public void get(){
        System.out.println("采集苹果");
    }
}
public class Banana implements Fruit{
    /*
     * 采集
     */
     public void get(){
        System.out.println("采集香蕉");
    }
}

接下来创建一个水果工厂类FruitFactory,在工厂中实现对Apple和Banana类的实例化。

public class FruitFactory {
    /*
     * 获得Apple类的实例
     */
    public static  Fruit getApple(){
        return new Apple();
    }
     
    /*
     * 获得Banana类实例
     */
    public static Fruit getBanana(){
        return new Banana();
    }
}

若FruitFactory中getXXX()方法未声明为static的话,每次调用方法需创建FruitFactory实例比较麻烦,我们直接声明方法为static。

这样,我们就能够使用FruitFactory创建Apple和Banana实例对象了。 

public class Client{
    public static void main(String[] args){
 
     //实例化一个Apple
        Fruit apple = FruitFactory.getApple();
        Fruit banana = FruitFactory.getBanana();
        apple.get();
        banana.get();
    }
}

观察以上工厂,其为每一个水果具体类都添加了一个getXXX()方法,当水果种类增多时方法数量也会增加导致FruitFactory类比较臃肿,而且各个方法之间关系也不够紧密不符合“高内聚”原则,我们再对其进行优化。 

public class FruitFactory {
    /*
     * getFruit方法,获得所有产品对象
     */
     public static Fruit getFruit(String type) throws InstantiationException, IllegalAccessException{
        if(type.equalsIgnoreCase("apple")) {
            return Apple.class.newInstance();
        } elseif(type.equalsIgnoreCase("banana")) {
            return Banana.class.newInstance();
        } else{
            System.out.println("找不到相应的实例化类");
            return null;
        }
    }
}

在客户端,使用改良后的FruitFactory来创建Apple和Banana实例对象。

public class Client{
    public static void main(String[] args){
        Fruit apple = FruitFactory.getFruit("apple");
        Fruit banana = FruitFactory.getFruit("banana");
        apple.get();
        banana.get();
    }
}

运行程序打印结果如下: 

采集苹果 
采集香蕉

什么是工厂方法模式?

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

模式中包含的角色及其职责

  • 抽象工厂(Factory)角色:工厂方法模式的核心,所有具体工厂类都必须实现这个接口。
  • 具体工厂( ConcreteFactory)角色:具体工厂类是抽象工厂的一个实现,负责实例化具体的产品。
  • 抽象产品(Product)角色:工厂方法模式所创建的所有具体产品的父类,或约定所有具体产品类都应实现的公共接口。
  • 具体产品(ConcreteProduct)角色:工厂方法模式所创建的真正对象。

在简单工厂模式中我们了解了简单工厂模式,我们使用如下具体的工厂FruitFactory对所有的水果对象进行实例化,缺点是显而易见的:当有新品种的水果需要产生时就需要修改工厂的getFruit()方法,加入新品种水果的逻辑判断和业务代码,这极不符合java“开放--封闭”原则。 

public class FruitFactory {
    /*
     * get方法,获得所有产品对象
     */
     public static Fruit getFruit(String type) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        if(type.equalsIgnoreCase("apple")) {
            return Apple.class.newInstance();
            
        } else if(type.equalsIgnoreCase("banana")) {
            return Banana.class.newInstance();
        } 
        /*
         * 如果有新品种的水果需要生产需在此处增加相应逻辑判断及业务代码,例如:
         * else if(type.equalsIgnoreCase("pear")) {
         *         return Pear.class.newInstance();
         *    } 
         */
         else {
            System.out.println("找不到相应的实例化类");
            return null;
        }
    }
}

接下来我们使用工厂方法模式对以上工厂进行改进,首先工厂方法模式中FruitFactory被设计为了抽象工厂(可以是抽象类或者接口),它不再负责具体的产品创建,而是将产品的创建工作推迟到了由它的子类来实现,接下来以具体的代码为例。

抽象后的FruitFactory仅用来声明其所有子类需实现的接口。

public interface FruitFactory {
    public Fruit getFruit();
}

有了这个抽象工厂以后,假如我们需要苹果了该怎么办?很简单,创建一个生产苹果的工厂AppleFactory即可。

public class AppleFactory implements FruitFactory{
    public Fruit getFruit(){
        return new Apple();
    }
}

假如我们又需要获取香蕉了该怎么办?依旧简单,创建一个生产香蕉的工厂BananaFactory即可。

public class BananaFactory implements FruitFactory{
    public Fruit getFruit(){
        return new Banana();
    }
}

如果以后还有其他更多新品种的水果加入,只需要创建一个生产相应水果的工厂并让该工厂实现抽象工厂FruitFactory 的接口,需要哪种水果我们就调用相应工厂的getFruit()方法得到水果,这样做有一个好处,无论我们增加多少种水果,我们只需增加一个生产相应水果的工厂即可,无需对现有的代码进行修改,这就很好的符合了"开放--封闭"原则。开闭原则:https://blog.csdn.net/weixin_62458944/article/details/132070314?spm=1001.2014.3001.5501

什么是抽象工厂模式

抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。

此处引入了一个新的概念产品族,那什么是产品族呢?百度一下:产品族是以产品平台为基础,通过添加不同的个性模块,以满足不同客户个性化需求的一组相关产品。

所谓产品族通俗来说即是:具有某一共性的一系列相关产品.以前面的Apple(苹果),Banana(香蕉),Pear(梨)为例,Apple(苹果),Banana(香蕉),Pear(梨)这三种水果对应上图中的产品等级结构。

这三种水果有产自南方的,也有产自北方的,北方和南方则对应上图中的产品族,产自北方的Apple(苹果),Banana(香蕉),Pear(梨)就构成一个产品族,它们的共性是产自北方,同样产自南方的Apple(苹果),Banana(香蕉),Pear(梨)也构成了一个产品族。 

模式中包含的角色及其职责

  • 抽象工厂(Factory)角色:抽象工厂模式的核心,包含对多个产品等级结构的声明,任何工厂类都必须实现这个接口。
  • 具体工厂(ConcreteFactory)角色:具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品对象。
  • 抽象(Product)角色:抽象模式所创建的所有对象的父类,或声明所有具体产品所共有的公共接口。
  • 具体产品(ConcreteProduct)角色:抽象工厂模式所创建的真正实例。 

总结:抽象工厂中的方法对应产品等级结构,具体工厂对应产品族。

接下来用代码进行说明:保留之前工厂方法模式中的Fruit接口,用来负责描述所有水果实例应该共有的方法。

public interface Fruit {
	/*
	 * 采集
	 */
	public void get();
}

此时Apple(苹果)和Banana(香蕉)将不再是具体的产品类而是抽象类,因为它们还需要进一步划分北方和南方两个产品族。

public abstract class Apple implements Fruit{
	/*
	 * 采集
	 */
	public abstract void get();
}
public abstract class Banana implements Fruit{
	/*
	 * 采集
	 */
	public abstract void get();
}

再进一步细分,苹果(Apple)被具体化为北方苹果(NorthApple)和南方苹果(SouthApple)。

public class NorthApple extends Apple {

	public void get() {
		System.out.println("采集北方苹果");
	}

}
public class SouthApple extends Apple {

	public void get() {
		System.out.println("采集南方苹果");
	}

}

香蕉(Banana)被具体化为北方香蕉(NorthBanana)和南方香蕉(SouthBanana).

public class NorthBanana extends Banana {

	public void get() {
		System.out.println("采集北方香蕉");
	}

}
public class SouthBanana extends Banana {

	public void get() {
		System.out.println("采集南方香蕉");
	}

}

继续写工厂,与之前的FruitFactory有所不同,此时的FruitFactory需为每一个产品等级结构添加获取方法声明。

public interface FruitFactory {
	//实例化Apple
	public Fruit getApple();
	//实例化Banana
	public Fruit getBanana();
}

为每一个产品族添加相应的工厂,NorthFruitFactory负责生产所有北方的水果,SouthFruitFactory负责生产所有南方的水果。

public class NorthFruitFactory implements FruitFactory {

	public Fruit getApple() {
		return new NorthApple();
	}

	public Fruit getBanana() {
		return new NorthBanana();
	}

}
public class SouthFruitFactory implements FruitFactory {

	public Fruit getApple() {
		return new SouthApple();
	}

	public Fruit getBanana() {
		return new SouthBanana();
	}

}

在客户端中进行测试,代码如下。

public class Client {
	public static void main(String[] args) {

		FruitFactory ff1 = new NorthFruitFactory();
		Fruit apple1 = ff1.getApple();
		apple1.get();

		Fruit banana1 = ff1.getBanana();
		banana1.get();

		FruitFactory ff2 = new SouthFruitFactory();
		Fruit apple2 = ff2.getApple();
		apple2.get();

		Fruit banana2 = ff2.getBanana();
		banana2.get();
	}
}

运行程序打印结果如下:

采集北方苹果
采集北方香蕉
采集南方苹果
采集南方香蕉

工厂模式的优缺点

优点

  • 封装对象的创建过程:工厂模式将对象的创建过程封装到工厂类中,避免了客户端直接依赖具体的产品类,从而提高了代码的可维护性和可扩展性。
  •  创建多个产品族或产品等级结构:当需要创建多个产品族或产品等级结构时,工厂模式可以提供一个统一的接口,方便客户端进行调用。
  •  符合开闭原则:当需要添加新的产品时,只需要增加相应的产品类和工厂方法即可,不需要修改原有的代码,符合开闭原则。

缺点

  1.  增加代码复杂度:工厂模式需要增加额外的工厂类,增加了代码的复杂度。
  2.  增加系统的抽象性和理解难度:由于工厂模式引入了抽象层,因此增加了系统的抽象性和理解难度。

工厂模式运用场景

工厂模式适用于以下场景:

  1. 需要创建多个产品族或产品等级结构:当需要创建多个产品族或产品等级结构时,工厂模式可以提供一个统一的接口,方便客户端进行调用。
  2. 需要封装对象的创建过程:当对象的创建过程比较复杂,或者需要依赖其他类的时候,可以使用工厂模式来封装对象的创建过程。
  3. 需要动态切换产品:当需要动态切换产品时,工厂模式可以提供一个统一的接口,方便客户端进行调用。

总结

工厂模式是一种常见的设计模式,用于创建对象的过程中,通过工厂类来封装对象的创建过程。工厂模式具有封装对象的创建过程、创建多个产品族或产品等级结构、符合开闭原则等优点,同时也存在增加代码复杂度、增加系统的抽象性和理解难度等缺点。在实际的开发中,我们可以根据具体的需求来选择使用工厂模式或其他设计模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/61670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索国产嵌入式Python解决方案的方法(开源)

大家好,今天我们要介绍一款适用于单片机的嵌入式Python开源项目 -- PikaPython。 第一:嵌入式Python的发展趋势 在嵌入式领域软硬件的发展趋势中,硬件的成本日益降低,性能逐渐提升。这种趋势使得Python在芯片上的运行难度已经大大…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 4

知识点:什么是掌控板? 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED…

物联网平台使用笔记

阿里云的IOT平台限制了50个设备。排除 移动云的限制较少,这里试用下。 创建完产品,接入设备后。使用MQTT客户端测试 其中client id 为设备id, username 为产品id, password 可以使用设备调试那里生成的。或使用官方token.exe 生成…

7.1.tensorRT高级(2)-使用openvino进行onnx的模型推理过程

目录 前言1. openvino2. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。 本次课程学习 tensorRT 高级-使用 openvino 进行 onnx…

ChatGPT3.5——AI人工智能是个什么玩意?

ChatGPT3.5——AI人工智能 AI人工智能什么是AI?AI有什么过人之处AI有什么缺点 AI的发展AI的发展史中国是如何发展AI的 AI六大要素感知理解推理学习交互 ChatCPT-3.5GPT-3.5的优势在哪里GPT-3.5的风险GPT-4骗人事件 AI人工智能 AI,就像是一位超级聪明的机…

地级市经济增长质量指数及原始数据(2006-2018年)

二十大报告强调,高质量发展是全面建设社会主义现代化国家的首要任务。研究表明,知识产权示范城市建设显著提高了城市经济增长质量,且这种促进作用具有持续性,地方政府财政支出偏向的改变以及知识产权司法保护和行政保护力度的提升…

关系型数据库的设计

范式 关系 注意:根据阿里开发规范,不再设置数据库的外键,在应用层保证外键逻辑即可 数据库设计 1:1 1:n 设想学生-班级案例,若在班级中保存所有学生的主键,则表长不好预测,表的数据亢余。 所以是在多的…

Maven设置阿里云路径(防止加载过慢)

<?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding …

【雕爷学编程】Arduino动手做(184)---快餐盒盖,极低成本搭建机器人实验平台3

吃完快餐粥&#xff0c;除了粥的味道不错之外&#xff0c;我对个快餐盒的圆盖子产生了兴趣&#xff0c;能否做个极低成本的简易机器人呢&#xff1f;也许只需要二十元左右 知识点&#xff1a;轮子&#xff08;wheel&#xff09; 中国词语。是用不同材料制成的圆形滚动物体。简…

外卖多门店小程序开源版开发

外卖多门店小程序开源版开发 外卖多门店小程序开源版的开发可以按照以下步骤进行&#xff1a; 确定需求&#xff1a;明确外卖多门店小程序的功能和特点&#xff0c;包括用户注册登录、浏览菜单、下单支付、订单管理等。技术选型&#xff1a;选择适合开发小程序的技术框架&…

Pytest学习教程_测试报告生成pytest-html(三)

前言 pytest-html 是一个用于生成漂亮的 HTML 测试报告的 pytest 插件。它可以方便地将 pytest 运行的测试结果转换为易于阅读和理解的 HTML 报告&#xff0c;提供了丰富的测试结果展示功能和交互性。 一、安装 # 版本查看命令 pytest版本&#xff1a; pytest --version pyte…

Kubernetes 整体架构介绍

架构图 Kubernetes 主要由以下几个核心组件组成&#xff1a; etcd 保存了整个集群的状态&#xff1b;kube-apiserver 提供了资源操作的唯一入口&#xff0c;并提供认证、授权、访问控制、API 注册和发现等机制&#xff1b;kube-controller-manager 负责维护集群的状态&#xf…

SpringBoot 升级内嵌Tomcat

SpringBoot 更新 Tomcat 最近公司的一个老项目需要升级下Tomcat&#xff0c;由于这个项目我完全没有参与&#xff0c;所以一开始我以为是一个老的Tomcat项目&#xff0c;升级它的Tomcat依赖或者是Tomcat容器镜像&#xff0c;后面发现是一个SpringBoot项目&#xff0c;升级的是…

Rpc异步日志模块

Rpc异步日志模块作用 在一个大型分布式系统中&#xff0c;任何部署的分布式节点都可能发生崩溃&#xff0c;试想如果用普通的办法&#xff0c;即先排查哪个节点down掉了&#xff0c;找到down掉的节点后采取调试工具gdb调试该节点&#xff0c;进而排查宕机的原因。这中排查方法…

考研408 | 【计算机网络】物理层

导图&#xff1a; 一、通信基础 基本概念&#xff1a; 物理层接口特性&#xff1a;物理层解决如何在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 物理层主要任务&#xff1a;确定与传输媒体接口有关的一些特性 典型的数据通信模型 数据通…

PLL 的 verilog 实现

锁相环&#xff08;PLL&#xff09;是一种常用的频率、相位追踪算法&#xff0c;在信号解调、交流并网等领域有着广泛的应用。本文对全数字锁相环的原理进行介绍&#xff0c;随后给出 verilog 实现及仿真。 PLL 锁相原理 锁相环结构如下图所示&#xff0c;主要由鉴相器、环路滤…

4.DNS和负载均衡

文章目录 coreDNS概念部署croeDNS测试 kubernetes多master集群结构master节点部署 负载均衡配置部署nginx做四层反向代理安装高可用 keepalivednginx监控脚本修改k8s中组件的配置文件 coreDNS 概念 coreDNS是kubernetes的默认DNS实现。可以为集群中的service资源创建一个资源名…

【Unity3D】消融特效

1 前言 选中物体消融特效中基于 Shader 实现了消融特效&#xff0c;本文将基于 Shader Graph 实现消融特效&#xff0c;两者原理一样&#xff0c;只是表达方式不同&#xff0c;另外&#xff0c;选中物体消融特效中通过 discard 丢弃片元&#xff0c;本文通过 alpha 测试丢弃片元…

idea 2023 新版ui中git的相关操作

前两个月换了新电脑&#xff0c;下了最新版的idea发现可以切换一套新的ui了 切换新ui肯定不太习惯&#xff0c;很多操作都得重新摸索一下 在这里记录几个git相关的操作 忽略我下面截图中当前项目是js的后端项目…… 切换ui 首先说一下怎么切换新旧版ui&#xff0c;我这里就…

Spring很常用的@Conditional注解的使用场景和源码解析

介绍 今天要分享的是Spring的注解Conditional&#xff0c;Conditional是一个条件注解&#xff0c;它的作用是判断Bean是否满足条件&#xff0c;如果满足条件&#xff0c;则将Bean注册进IOC中&#xff0c;如果不满足条件&#xff0c;则不进行注册&#xff0c;这个注解在SpringB…