Java设计模式:工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)

❤ 作者主页:欢迎来到我的技术博客😎
❀ 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得关注点赞收藏评论⭐️⭐️⭐️
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉

文章目录

  • 一、为什么需要工厂模式
  • 二、什么是工厂模式
  • 三、未使用工厂模式的案例
  • 四、简单工厂模式
    • 1. 简单工厂模式的定义
    • 2. 简单工厂模式的结构
    • 3. 简单工厂模式的实现
    • 4. 简单工厂模式的优缺点
  • 五、工厂方法模式
    • 1. 工厂方法模式的定义
    • 2. 工厂方法模式的结构
    • 3. 工厂方法模式的实现
    • 4. 工厂方法模式的优缺点
  • 六、抽象工厂模式
    • 1. 抽象工厂模式的定义
    • 2. 抽象工厂模式的结构
    • 3. 抽象工厂模式的实现
    • 4. 抽象工厂模式的优缺点
  • 七、工厂模式总结

一、为什么需要工厂模式

在软件开发中,创建对象实例最常用的方式就是通过 new 操作符直接生成对象,但是有时候需要根据不同的条件来创建不同类型的对象,而直接在代码中使用 new 关键字创建对象会导致代码的耦合度增加,不利于系统的维护和扩展。在这种情况中,创建对象不仅仅只是一个 操作,而是有一个复杂的 过程

因此,对于出现的这种的情况,我们怎么做到就是轻松方便地构造对象实例,而不用去关心对象实例的细节以及创建中的复杂流程呢?这时候我们引入 工厂类 来负责对象的创建。


二、什么是工厂模式

在工厂模式中,通常会定义一个 抽象工厂接口,该接口声明了创建对象的方法,具体的工厂类 实现了这个接口,并负责实际 创建对象的过程。客户端代码通过使用工厂接口来创建对象,而不直接使用 new 关键字实例化对象,从而实现 对象创建和使用的解耦

工厂模式可以分为三类:

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

这三种模式从上到下逐步抽象,并且更具一般性。在《设计模式》这本书中将工厂模式分为两类:工厂方法模式和抽象工厂模式,将简单工厂模式看作是工厂方法模式中的一种特例,在实际开发中,简单工厂模式反而更像是一种 编程习惯


三、未使用工厂模式的案例

在引入简单工厂模式之前,我们先来演示一下没有使用工厂模式的业务场景。

在没有使用工厂模式的情况下,当客户前往手机店购买苹果手机时,手机店必须亲自进行苹果手机的制造工作;同样,如果客户想购买小米手机,手机店也必须自行进行小米手机的制造工作。

类图如下:
在这里插入图片描述

具体的类设计如下:

手机抽象类:

public abstract class Phone {public abstract  String getName();//外观定制public void addAppearance() {System.out.println("外观定制");}//硬件配置public void addConfiguration() {System.out.println("硬件配置");}}

苹果手机类:

public class ApplePhone extends Phone {@Overridepublic String getName() {return "苹果手机";}
}

小米手机类:

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

手机店类:

public class PhoneStore {public Phone orderPhone(String type) {//声明Phone类型的变量,根据不同类型创建不同的phone子类对象Phone phone = null;if ("Apple".equals(type)) {phone = new ApplePhone();} else if ("Xiaomi".equals(type)) {phone = new XiaomiPhone();} else {throw new RuntimeException("暂没有该手机型号");}//配置phone.addAppearance();phone.addConfiguration();return phone;}}

客户端类:

public class Client {public static void main(String[] args) {//1. 创建手机店类PhoneStore store = new PhoneStore();//2. 购买手机Phone phone = store.orderPhone("Apple");System.out.println(phone.getName());}}

至此,客户就可以在客户端中购买所需要什么品牌的手机,然后由手机店自己去制造手机后交付于客户。

说明:
在上述代码中 Phone 类被声明为抽象类,在抽象类中声明了一个抽象方法 getName(),但是没有具体的实现方法,而具体的实现留给子类去完成。其他两个方法是具体的实现方法,子类继承直接默认获得这两个功能,不需要再去实现。

这时候我们可以发现,这不就和接口特别相似,但是两者却有着不同之处,接下来我们讲一下 抽象类接口 区别:

抽象类:

  • 可以包含抽象方法和具体方法;
  • 可以包含字段(成员变量);
  • 不能被实例化,需要通过继承来使用;
  • 一个类只能继承一个抽象类;

接口:

  • 只能包含抽象方法;
  • 不能包含字段(成员变量);
  • 所有方法默认为 public,所有字段默认为 public, static, final
  • 可以被多个类继承(支持多重继承);

四、简单工厂模式

通过上面的案例,我们看到手机店不仅要卖手机还要自己去制造手机。因此我们引入了工厂模式,我们可以使用简单工厂模式来创建一个工厂类,由工厂类去实现手机的制造,而用户只需要在客户端传入工厂类的参数,工厂类就会去制造相对应的手机出来,手机店只需去卖给客户需要的手机即可,不需要关心手机是如何被制造出来的整个过程。

1. 简单工厂模式的定义

简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,当需要改变的时候,只需要修改工厂类即可。


2. 简单工厂模式的结构

简单工厂模式包含以下的角色:

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

3. 简单工厂模式的实现

使用简单工厂模式对上面案例进行改造,类图如下:
在这里插入图片描述
 
具体的类设计如下:

对于手机抽象类、苹果手机类、小米手机类、客户端这几个类我们都不需要进行修改,我们只需要修改手机店类以及创建一个工厂类即可。

工厂类:

public class SimplePhoneFactory {public Phone createPhone(String type) {//声明Phone类型的变量,根据不同类型创建不同的phone子类对象Phone phone = null;if ("Apple".equals(type)) {phone = new ApplePhone();} else if ("Xiaomi".equals(type)) {phone = new XiaomiPhone();} else {throw new RuntimeException("暂没有该手机型号");}//配置phone.addAppearance();phone.addConfiguration();return phone;}
}

手机店类:

public class PhoneStore {public Phone orderPhone(String type) {//创建工厂类对象SimplePhoneFactory factory = new SimplePhoneFactory();//调用制造手机的方法Phone phone = factory.createPhone(type);//配置phone.addAppearance();phone.addConfiguration();return phone;}}

4. 简单工厂模式的优缺点

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

缺点:
每次添加新产品就需要修改工厂类,不符合 “开闭原则”。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。


对上面提到的 开闭原则 进行讲解,开闭原则(Open/Closed Principle,OCP)是面向对象设计中一个重要原则,它包含了两个核心概念:

  1. 对扩展开发: 意味着在不修改现有代码的情况下,可以通过添加新的功能来扩展系统的功能。新功能的添加应该是通过添加新的类、模块、接口等方式进行的,而不是通过修改已有的代码。
  2. 对修改关闭: 意味着已经存在的代码不应该被修改,因为修改可能引入错误,破坏原有的稳定性。系统的行为可以通过扩展来改变,但不应该通过修改已有的代码来实现。

五、工厂方法模式

1. 工厂方法模式的定义

针对上述简单工厂模式中的缺点,使用 工厂方法模式 就可以完美解决,完全遵循开闭原则。

工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品时,只需增加该 产品类 以及该产品对应的 具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。


2. 工厂方法模式的结构

工厂方法模式包含以下的角色:

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

3. 工厂方法模式的实现

使用工厂方法模式对上面案例进行改造,类图如下:
在这里插入图片描述
 
具体的类设计如下:
对于手机抽象类、苹果手机类、小米手机类这几个类不需要修改,而手机店类和客户端类需要修改,并且新增抽象工厂(手机工厂)、具体工厂(苹果手机工厂、小米手机工厂)。

手机工厂:

public interface PhoneFactory {Phone createPhone();
}

苹果手机工厂:

public class ApplePhoneFactory implements PhoneFactory {@Overridepublic Phone createPhone() {return new ApplePhone();}
}

小米手机工厂:

public class XiaomiPhoneFactory implements PhoneFactory {@Overridepublic Phone createPhone() {return new XiaomiPhone();}
}

手机店类:

public class PhoneStore {private  PhoneFactory factory;public void setFactory(PhoneFactory factory) {this.factory= factory;}public Phone orderPhone() {Phone phone = factory.createPhone();//配置phone.addAppearance();phone.addConfiguration();return phone;}}

客户端类:

public class Client {public static void main(String[] args) {//创建手机店对象PhoneStore store = new PhoneStore();//创建对象
//        ApplePhoneFactory factory = new ApplePhoneFactory();XiaomiPhoneFactory factory = new XiaomiPhoneFactory();store.setFactory(factory);//购买手机Phone phone = store.orderPhone();System.out.println(phone.getName());}}

4. 工厂方法模式的优缺点

优点:

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

缺点:

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

六、抽象工厂模式

首先,我们上述案例再新增点需求,比如我们还要生产苹果手表和小米手表等产品,按照工厂方法模式的话我们需要去创建每个产品对应的产品类以及对应的具体工厂类,如果新增的产品很多的话,那么很容易发生类爆炸情况。

我们试想一下可不可以这样实现,就是属于同一品牌的产品可以由同一工厂类去创建,比如创建一个苹果工厂类,它就可以同时生产出苹果手机和苹果手表等都属于苹果品牌的产品出来。因此,我们就引入了 抽象工厂模式

1. 抽象工厂模式的定义

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

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产 一个等级 的产品,而抽象工厂模式可生产 多个等级 的产品。
 

使用抽象工厂模式一般要满足以下条件:

  • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品;
  • 系统一次只能消费其中某一族产品,即同族的产品一起使用;

在介绍抽象工厂模式前,我们先理解一下产品等级和产品族这两个在软件设计中经常出现的概念:

产品等级

  • 产品等级指的是具有共同特性的产品集合,它们通常是在某个方面上具有共性或者属于同一类别的产品。
  • 例如,在汽车制造中,轿车、卡车和摩托车都可以构成不同等级的产品。它们都是交通工具,但在功能、结构和用途上有所不同。

产品族

  • 产品族是指不同等级产品中相关联的一组产品集合,它们之间可能存在某种内在的联系或者依赖关系。
  • 比如,在汽车制造中,汽车可能有多种不同型号,每种型号都有不同的配置和特点,比如轿车产品族可能包括轿车、跑车、SUV等不同类型。

为了方便理解,我们看一下产品等级和产品族的示意图:

在这里插入图片描述


2. 抽象工厂模式的结构

抽象工厂模式包含以下的角色:

  • 抽象工厂 : 提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
  • 具体工厂 :主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  • 抽象产品 : 定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  • 具体产品 : 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

3. 抽象工厂模式的实现

使用抽象工厂模式对上面的案例进行改造,类图如下:
在这里插入图片描述

 
具体的类设计如下:
对于手机抽象类、苹果手机类、小米手机类这几个类不需要修改,而客户端类、抽象工厂类需要修改,并且新增手表抽象类、苹果手表类、小米手表类、苹果工厂类、小米工厂类。

手表抽象类:

public abstract class Watch {public abstract String getName();
}

苹果手表类:

public class AppleWatch extends Watch {@Overridepublic String getName() {return "苹果手表";}
}

小米手表类:

public class XiaomiWatch extends Watch {@Overridepublic String getName() {return "小米手表";}
}

抽象工厂类:

public interface PhoneAndWatchFactory {//生产手机的功能Phone createPhone();//生产手表的功能Watch createWatch();
}

苹果工厂类:

public class AppleFactory implements PhoneAndWatchFactory {@Overridepublic Phone createPhone() {return new ApplePhone();}@Overridepublic Watch createWatch() {return new AppleWatch();}
}

小米工厂类:

public class XiaomiFactory implements PhoneAndWatchFactory {@Overridepublic Phone createPhone() {return new XiaomiPhone();}@Overridepublic Watch createWatch() {return new XiaomiWatch();}
}

客户端类:

public class Client {public static void main(String[] args) {//创建的是苹果工厂对象AppleFactory factory = new AppleFactory();//获取苹果手机和苹果手表Phone phone = factory.createPhone();Watch watch = factory.createWatch();System.out.println(phone.getName());System.out.println(watch.getName());}
}

4. 抽象工厂模式的优缺点

优点:

  • 抽象工厂模式能够确保创建的产品族是相互关联、一致的。这意味着通过抽象工厂创建的对象能够相互配合使用,形成一个完整的系统。
  • 由于客户端通过抽象接口使用产品,因此更换产品系列相对容易。只需要更改具体工厂的实例,而不需要修改客户端代码。
  • 新增一个产品族的实现,只需扩展抽象工厂和具体工厂,而不需要修改已有代码,符合开闭原则。

缺点:

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

七、工厂模式总结

简单工厂模式: 让一个工厂类负责创建所有对象;但没有考虑后期扩展和维护,修改违背开闭原则,静态方法不能被继承。

工厂方法模式: 主要思想是继承,修改符合开闭原则;但每个工厂只能创建一种类型的产品。

抽象工厂模式: 主要思想是组合,本质是产品族,实际包含了很多工厂方法,修改符合开闭原则;但只适用于增加同类工厂这种横向扩展需求,不适合新增功能方法这种纵向扩展。

其实这三种工厂模式在形式和特点上都非常相似,甚至存在一定的内在联系,而且最终目的都是解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为它们之间也是可以灵活转变的。


 
非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 分享👥 留言💬thanks!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第五讲观测值中与卫星、接收机有关的误差 第六讲观测值中与信号传播路径有关的误差以及电离层、对流层相关模型 | GNSS(RTK)课程学习笔记day3

说明:以下笔记来自计算机视觉life吴桐老师课程:从零掌握GNSS、RTK定位[链接],从零掌握RTKLIB[链接]。非原创!且笔记仅供自身与大家学习使用,无利益目的。 第五讲 观测值中与卫星、接收机有关的误差 卫星轨道误差 由卫…

Kafka-Kafka核心参数详解

Kafka的HighLevel API使用是非常简单的,所以梳理模型时也要尽量简单化,主线清晰,细节慢慢扩展。 Kafka提供了两套客户端API,HighLevel API和LowLevel API。 HighLevel API封装了kafka的运行细节,使用起来比较简单&…

jQuery实现轮播图代码

简述 一个简单的jQuery轮播图代码,首先,定义了一个slideshow-container的div容器,其中包含了所有轮播图幻灯片。每个幻灯片都包含一个mySlides的类名,并且使用CSS将其隐藏。然后,使用JavaScript代码来控制幻灯片的显示和隐藏。在showSlides()函数中,遍历所有幻灯片并将它…

【项目管理】redmine

Redmine是用Ruby开发的基于web的项目管理软件,是用ROR框架开发的一套跨平台项目管理系统,据说是源于Basecamp的ror版而来,支持多种数据库,有不少自己独特的功能,例如提供wiki、新闻台等,还可以集成其他版本…

Flutter实现丝滑的滑动删除、移动排序等-Dismissible控件详解

文章目录 Dismissible 简介使用场景常用属性基本用法举例注意事项 Dismissible 简介 Dismissible 是 Flutter 中用于实现可滑动删除或拖拽操作的一个有用的小部件。主要用于在用户对列表项或任何其他可滑动的元素执行删除或拖动操作时,提供一种简便的实现方式。 使…

大数据处理与分析-Spark

导论 (基于Hadoop的MapReduce的优缺点) MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架 MapReduce是一种用于处理大规模数据集的编程模型和计算框架。它将数据处理过程分为两个主要阶段:Map阶…

(2021|EMNLP,CLIP,CLIPScore,RefCLIPScore)CLIPScore:图像标题的无参考评估指标

CLIPScore: A Reference-free Evaluation Metric for Image Captioning 公z号:EDPJ(添加 VX:CV_EDPJ 或直接进 Q 交流群:922230617 获取资料) 目录 0. 摘要 1. 简介 2. 相关工作 3. CLIPScore 4. 标题评估基准 …

yolov5障碍物识别-雪糕筒识别(代码+教程)

简介 这是一个检测交通锥并识别颜色的项目。我使用 yolov5 来训练和检测视锥细胞。此外,我使用 k 均值来确定主色,以对锥体颜色进行分类。目前,支持的颜色为红色、黄色、绿色和蓝色。其他颜色被归类为未知。 数据集和注释 我使用了一个自收…

Open5GSUeRANSim3:VirtualBOX VM使用static IP并和host互通

本文档参考 https://blog.csdn.net/shuaihj/article/details/127589833 https://www.cnblogs.com/manongqingcong/articles/16659150.html https://blog.csdn.net/justlpf/article/details/132977047 VM默认使用的是自动分配的IP,每个VM的ip都是10.0.2.15。后续为了…

12.19_黑马数据结构与算法笔记Java

目录 203 排序算法 选择排序 204 排序算法 堆排序 205 排序算法 插入排序 206 排序算法 希尔排序 207 排序算法 归并排序 自顶至下 208 排序算法 归并排序 自下至上 209 排序算法 归并加插入 210 排序算法 单边快排 211 排序算法 双边快排 212 排序算法 快排 随机基准…

ITIL® 4 Foundation​,12月23日即将开课~想了解点击查看

ITIL 4 Foundation即将开课~ 想报名的必须提前预约啦 👇👇👇 培训地点: 远程直播:线上平台学习 开课时间: 周末班:12月23日、24日; 什么是ITIL? 信息技术基础架构…

将Abp默认事件总线改造为分布式事件总线

文章目录 原理创建分布式事件总线实现自动订阅和事件转发 使用启动Redis服务配置传递Abp默认事件传递自定义事件 项目地址 原理 本地事件总线是通过Ioc容器来实现的。 IEventBus接口定义了事件总线的基本功能,如注册事件、取消注册事件、触发事件等。 Abp.Events…

LTD256次升级 |一分钟创建小程序官网 • 官网内容可在小程序分享

1、 商品关联表单支持上传图片; 2、 「我的咨询」新增快捷添加入口; 3、 极速官微新增官网内容分享页面;优化创建流程; 4、 极速官微支持编辑方式添加文章与产品; 5、 极速官微新增数据枢纽入口与网站设置页面&#xf…

(9)Linux Git的介绍以及缓冲区

💭 前言 本章我们先对缓冲区的概念进行一个详细的探究,之后会带着大家一步步去编写一个简陋的 "进度条" 小程序。最后我们来介绍一下 Git,着重讲解一下 Git 三板斧,一般只要掌握三板斧就基本够用了。 缓冲区&#xff…

邮政快递单号查询入口,标记需要的单号记录

批量查询邮政快递单号的物流信息,对需要的单号记录进行标记。 所需工具: 一个【快递批量查询高手】软件 邮政快递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,并登录 步骤2:点击主界面左上角…

一文教你提高写代码效率,程序员别错过!

首先,每个程序员都是会利用工具的人,也有自己囊里私藏的好物。独乐乐不如众乐乐,今天笔者整理了 3 个辅助我们写代码的黑科技,仅供参考。如果你有更好的工具,欢迎评论区分享。 1、Google/Stackoverflow——搜索解决方…

Guideline 2.3.2 - Performance - Accurate Metadata问题如何解决

当您的应用程序在苹果应用商城审核过程中被拒绝时,苹果会向您发送一封邮件,其中提供了关于拒绝原因的详细信息。本文将指导您如何正确处理Guideline 2.3.2 - Performance - Accurate Metadata问题,并提供解决方案,以确保您的应用程…

RK3568 android11 调试mipi摄像头 gc2093

一,摄像头简介 GC2093是一个高质量的1080P CMOS图像传感器,用于安全相机产品、数码相机产品和手机相机应用程序。包含了一个1920H x 1080V像素阵列、片上10位ADC和图像信号处理器。高性能和低功耗功能的全面集成使GC2093最适合设计,减少了实…

安全运营之安全加固和运维

安全运营是一个将技术、流程和人有机结合的复杂系统工程,通过对已有安全产品、工具和服务产出的数据进行有效的分析,持续输出价值,解决安全问题,以确保网络安全为最终目标。 安全加固和运维是网络安全运营中的两个重要方面。 安全…

【Proteus仿真】【Arduino单片机】视力保护仪

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器,使LCD1602液晶,DS18B20温度传感器、按键、蜂鸣器、继电器开关、HC05蓝牙模块等。 主要功能: 系统运行后,LCD16…