设计模式之创建型模式---工厂模式

文章目录

  • 工厂模式概述
  • 简单工厂
    • 简单工厂的代码实现
    • 简单工厂的使用
    • 简单工厂应用场景
  • 工厂方法
    • 工厂方法模式的代码实现
    • 工厂方法的使用
    • 工厂方法应用场景
  • 抽象工厂
    • 抽象工厂模式代码实现
    • 抽象工厂的使用方法
    • 抽象工厂模式的应用场景
  • 总结

在这里插入图片描述

工厂模式概述

工厂模式从名字就能看出,这种模式是用于创建对象的,因为现实生活中,工厂就是用于生产产品的嘛。所以工厂模式的名字起得非常的贴近生活。工厂模式根据应用场景的不同,分为简单工厂,工厂方法,和抽象工厂三种。现实生活中的工厂有的可以生产几种产品,客户根据工厂提供的产品定制就行。比如生产A,B两种品牌的车。这种情况对应到工厂设计模式中就是简单工厂模式。用户只需要给工厂说我要A或者B品牌的车就行。但是如果用户说我想要C品牌的车,这时就难受了,工厂得需要做改建,增加C品牌产线等工作,非常繁琐,于是就出现了特定的工厂,比如生产A品牌车的工厂,生产B品牌的工厂。但是工厂也不能乱建,必须按照总公司的标准建造。所以这种工厂对应到设计模式中就是工厂方法模式,当用户需要新品牌的车时,直接按照总公司标准建造新的工厂就行,不影响之前的工厂工作。但是这种每新加一个品牌的车就得建一个工厂的方法确实比较奢侈,因为可能没那么多的土地,所以我们就可以让我们的工厂承担更多的任务,比如在造车的同时,咱们还可以造手机。这种工厂对应到设计模式中就是抽象工厂模式。

工厂模式的好处就是客户不需要知道对象的创建过程,只是通过简单的调用就能拿到自己想要的对象,这也是工厂设计模式的初衷,屏蔽复杂的对象构造过程,让调用方能通过简单的接口获取到自己想要的对象。从上面的例子我们也可以得出一个结论,就是根据我们的实际场景选择对应的工厂设计模式。比如就很简单的几个对象,咱们使用简单工厂模式就行。对应到生活中的例子就是,有多少钱,干多少事,本来就只有造两种品牌的车的钱,咱们就不要到处建工厂了。

简单工厂

假如我们要创建的产品不多,只要一个工厂类就可以,这种模式就称为简单工厂模式,比如我们就生产CarA 和CarB两种车,那么直接用一个工厂类就可以了,没有必要花钱建多个工厂。简单工厂的类图如下所示。
在这里插入图片描述
根据类图我们用JAVA实现下这个造车的过程。
注意:例子只是为了方便介绍本文的内容,不具有真实造车的参考价值

简单工厂的代码实现

根据类图,我们首先创建一个接口表示我们要造的所有车具有的行为,比如都需要安装引擎,轮子,刷颜色等行为。

public interface ICar {// 粉刷车身的颜色void printColor();// 安装车的引擎void installEngine();// 安装车的轮子void installWheels();// 安装车载操作系统void installSystem();
}

然后创建两个产品CarA和CarB,并且都继承实现ICar的接口。

public class CarA implements ICar {private String color;private String engine;private String wheels;private String system;@Overridepublic void printColor() {System.out.println("CarA 的颜色是红色");color = "RED";}@Overridepublic void installEngine() {System.out.println("安装 CarA 的引擎");engine = "A-Engine";}@Overridepublic void installWheels() {System.out.println("安装 CarA 的轮子");wheels = "A牌轮子";}@Overridepublic void installSystem() {System.out.println("安装 CarA 的车载系统");system = "A OS";}@Overridepublic String toString() {return "CarA{" +"color='" + color + '\'' +", engine='" + engine + '\'' +", wheels='" + wheels + '\'' +", system='" + system + '\'' +'}';}
}
public class CarB implements ICar {private String color;private String engine;private String wheels;private String system;@Overridepublic void printColor() {System.out.println("CarB 的颜色是蓝色");color = "Blue";}@Overridepublic void installEngine() {System.out.println("安装 CarB 的引擎");engine = "B-Engine";}@Overridepublic void installWheels() {System.out.println("安装 CarB 的轮子");wheels = "B牌轮子";}@Overridepublic void installSystem() {System.out.println("安装 CarB 的车载系统");system = "B OS";}@Overridepublic String toString() {return "CarB{" +"color='" + color + '\'' +", engine='" + engine + '\'' +", wheels='" + wheels + '\'' +", system='" + system + '\'' +'}';}
}

然后我们新建一个简单工厂类,通过一个buildCar方法构建我们的CarA和CarB两种车的对象

public class SimpleCarFactory {public static final String CAR_A = "CAR_A";public static final String CAR_B = "CAR_B";public static ICar buildCar(String type){ICar car = null;if(CAR_A.equals(type)){car = new CarA();}if(CAR_B.equals(type)){car =  new CarB();}if(car != null){car.printColor();car.installEngine();car.installWheels();car.installSystem();}return car;}
}

简单工厂的使用

我们建立一个Client类演示如何使用简单工厂

public class Client {public static void main(String[] args) {// 简单工厂ICar carA = SimpleCarFactory.buildCar(SimpleCarFactory.CAR_A);System.out.println("build a car A: " + carA);ICar carB = SimpleCarFactory.buildCar(SimpleCarFactory.CAR_B);System.out.println("build a car B: " + carB);}

运行结果:
在这里插入图片描述

简单工厂应用场景

对于产品种类相对较少的情况,比如我们做相机开发时,Android的系统相机支持多种种API,Camera1和Camera2以及后面的CameraX,这里我们就可以使用简单工厂模式,去根据具体的应用场景获取对应的CameraA对象。

工厂方法

简单工厂确实简单好用,但是缺点也很明显,每增加一种产品就需要增加一个具体的产品类并且修改工厂类,这违背开闭原则(开闭原则是指我们的程序应该对修改关闭,对扩展开放),就比如我们此时如果要造CarC,但我们只有一个工厂,所以就需要我们去在当前的工厂上修改以保证能够造CarC产品。这时小伙伴可能会说,那么再建一个工厂生产C产品就行了呀。对的,这就是工厂方法模式。工厂方法模式时对简单工厂模式的进一步抽象化。这样做的好处是可以使我们的程序在不修改原来代码的情况下引进新产品。从而满足开闭原则。这里还是以造车为例子。工厂方法的模式类图如下所示
在这里插入图片描述

工厂方法模式的代码实现

这里的ICar接口和对象使用的都是简单工厂部分的,代码一样,就不重复贴了。这里只贴新的代码。我们需要建立一个工厂的接口。定义工厂的功能是生产车,后面建造的工厂都必须以这个为标准,不能乱建。

public interface IFactory {ICar buildCar();
}

建立造CarA产品的工厂

public class ACarFactory implements IFactory{private ICar mCarA = new CarA();@Overridepublic ICar buildCar() {mCarA.printColor();mCarA.installEngine();mCarA.installWheels();mCarA.installSystem();return mCarA;}
}

建立造CarB产品的工厂

public class BCarFactory implements IFactory{private ICar mCarB = new CarA();@Overridepublic ICar buildCar() {mCarB.printColor();mCarB.installEngine();mCarB.installWheels();mCarB.installSystem();return mCarB;}
}

这样我们的工厂方法模式就实现了,这时假如我们要新增一个CarC 产品,我们只需要新增一个工厂类和一个产品C的类就可以了,符合开闭原则,代码如下:
新增产品C:

public class CarC implements ICar {private String color;private String engine;private String wheels;private String system;@Overridepublic void printColor() {System.out.println("CarC 的颜色是白色");color = "White";}@Overridepublic void installEngine() {System.out.println("安装 CarC 的引擎");engine = "C-Engine";}@Overridepublic void installWheels() {System.out.println("安装 CarC 的轮子");wheels = "C牌轮子";}@Overridepublic void installSystem() {System.out.println("安装 CarC 的车载系统");system = "C OS";}@Overridepublic String toString() {return "CarC{" +"color='" + color + '\'' +", engine='" + engine + '\'' +", wheels='" + wheels + '\'' +", system='" + system + '\'' +'}';}
}

建造产品C的工厂:

public class CCarFactory implements IFactory{private ICar mCarC = new CarC();@Overridepublic ICar buildCar() {mCarC.printColor();mCarC.installEngine();mCarC.installWheels();mCarC.installSystem();return mCarC;}
}

工厂方法的使用

同样我们新建一个Client类来演示工厂方法的使用

public class Client {public static void main(String[] args) {// 工厂方法IFactory mFactoryA = new ACarFactory();ICar mCarA = mFactoryA.buildCar();System.out.println("工厂方法模式构建 carA: " + mCarA);IFactory mFactoryB = new BCarFactory();ICar mCarB = mFactoryB.buildCar();System.out.println("工厂方法模式构建 carB: " + mCarB);IFactory mFactoryC = new CCarFactory();ICar mCarC = mFactoryC.buildCar();System.out.println("工厂方法模式构建 mCarC: " + mCarC);}
}

运行结果:
在这里插入图片描述

工厂方法应用场景

当我们的同种产品比较多的时候,可以考虑使用工厂方法模式,也就是说你开公司,目前只生产A,B两种产品,这两种产品都是车,只是一些构造的工艺技术有不同而已,但是未来你可能会继续增加你的同种类型的产品,比如生产C车,,这种情况就可以考虑使用工厂方法模式。工厂方法模式可以满足我们扩展新产品而不需要修改以前的工厂和产品。简单说就是:如果你造车,你的工厂就只是造车,生产手机,你的工厂就是只生产手机。工厂模式只考虑生产同种等级的产品,但读者可能会想,假如我一个工厂想造车又想生产手机怎么办呢?那就得用到抽象工厂模式了。

抽象工厂

如前面所说,工厂方法模式只考虑生产同种等级的产品,比如造车的工厂就只是造车,生产手机的工厂就只是生产手机,但是在我们的现实生活中,许多工厂是综合性的工厂,比如造车的工厂也能造手机。为啥这么设计呢?用工厂方法不是更好吗,想造手机,再建一个造手机的工厂不就行了吗?用毛爷爷的话说,理论上行得通,但实际上不可行,因为现在的很多公司都是综合性的公司,大公司会生产各种各样的产品,要是每种产品就建一个工厂,那么地球上的土地就这么点,哪里够用呀,所以综合性工厂可以解决这个问题。这里我们以造车的例子为基础,为工厂新增一个造手机的功能。类图如下:
在这里插入图片描述

抽象工厂模式代码实现

基于工厂方法的例子,我们新增一个产品手机,首先定义手机的公共接口:

public interface IPhone {// 刷上颜色void printColor();// 安装系统void installOS();
}

创建手机A

public class PhoneA implements IPhone{private String color;private String systemOs;@Overridepublic void printColor() {System.out.println("粉刷手机颜色为红色");color = "RED";}@Overridepublic void installOS() {System.out.println("安装手机的操作系统为Android系统");systemOs = "Android";}@Overridepublic String toString() {return "PhoneA{" +"color='" + color + '\'' +", systemOs='" + systemOs + '\'' +'}';}
}

创建手机B:

public class PhoneB implements IPhone{private String color;private String systemOs;@Overridepublic void printColor() {System.out.println("粉刷手机颜色为蓝色");color = "BLUE";}@Overridepublic void installOS() {System.out.println("安装手机的操作系统为IOS系统");systemOs = "IOS";}@Overridepublic String toString() {return "PhoneB{" +"color='" + color + '\'' +", systemOs='" + systemOs + '\'' +'}';}
}

然后我们定义我们要建的综合性工厂的标准接口

public interface IAbstractFactory {ICar buildCar();IPhone buildPhone();
}

新建两个综合性工厂,A和B,分别生产A品牌的产品和B品牌的产品。

// 生产A品牌的产品
public class AFactory implements IAbstractFactory {private ICar mCarA =new  CarA();private IPhone mPhoneA = new PhoneA();@Overridepublic ICar buildCar() {mCarA.printColor();mCarA.installEngine();mCarA.installWheels();mCarA.installSystem();return mCarA;}@Overridepublic IPhone buildPhone() {mPhoneA.printColor();mPhoneA.installOS();return mPhoneA;}
}
// 生产B品牌的产品
public class BFactory implements IAbstractFactory {private ICar mCarB =new CarB();private IPhone mPhoneB = new PhoneB();@Overridepublic ICar buildCar() {mCarB.printColor();mCarB.installEngine();mCarB.installWheels();mCarB.installSystem();return mCarB;}@Overridepublic IPhone buildPhone() {mPhoneB.printColor();mPhoneB.installOS();return mPhoneB;}
}

抽象工厂的使用方法

我们新建一个Client的类来演示抽象工厂的使用方法

public class Client {public static void main(String[] args) {// 抽象工厂IAbstractFactory mAFactory = new AFactory();ICar myAcar = mAFactory.buildCar();IPhone myAPhone = mAFactory.buildPhone();System.out.println("A工厂造的车: " + myAcar);System.out.println("A工厂造的手机: " + myAPhone);IAbstractFactory mBFactory = new BFactory();ICar myBcar = mBFactory.buildCar();IPhone myBPhone = mBFactory.buildPhone();System.out.println("B工厂造的车: " + myBcar);System.out.println("B工厂造的手机: " + myBPhone);}
}

运行结果:
在这里插入图片描述

抽象工厂模式的应用场景

当需要生产多种产品的时候,比如我们的工厂需要造车和造手机时,可以考虑使用抽象工厂模式,比如我们的电器厂,就可以考虑使用抽象工厂模式,因为电器厂既可以生产电视机也能生产空调。,农场也是,农场可以种植物,也可以养动物。

总结

本文主要以造车和手机的例子介绍了工厂模式的三种形式,简单工厂,工厂方法,抽象工厂的实现,并且在每节增加了类图和应用场景。读者可以根据应用场景和类图选择对应的工厂模式应用到自己的项目中,让自己的代码更加优雅和可维护。

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

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

相关文章

Threejs绘制传送带

接下来会做一个MES场景下的数字孪生,所以开始做车间相关的模型,不过还是尽量少用建模,纯代码实现,因为一方面可以动态使用,可以调节长度和宽度等, 下面这节就做一个简单的传送带,这是所有车间都…

基础SQL DML-插入语句

插入语句前,我们先创建一个表。表的创建在DDL语句里面涉及,可以参考:小赖同学吖-CSDN博客 我们创建一个员工表进行数据的插入操作 插入(添加)语句的语法 给员工表添加一条记录 给员工表添加多条记录 也可以通过下面的方…

年薪5.8万美元|临床医生赴美国康奈尔大学从事博士后研究

作为临床医学8年制的博士毕业生,A医生希望能到国外从事一段时间的博士后,以强化基础科研训练,弥补职业发展的短板。最终我们为其申请到康奈尔大学Weill Cornell医学院的博士后职位,年薪为5.8万美元。 A医生背景: 申请…

C语言项目实践——贪吃蛇

引言:本篇博客中,我将会使用结构体,链表,WIN32 API等一系列知识完成C语言项目——贪吃蛇的实现。在观看此篇博客之前,请将这些知识所熟悉,不然可能会造成理解困难。 更多有关C语言的知识详解可前往个人主页…

【C++】explicit关键字详解(explicit关键字是什么? 为什么需要explicit关键字? 如何使用explicit 关键字)

目录 一、前言 二、explicit关键字是什么? 三、构造函数还具有类型转换的作用 🍎单参构造函数 ✨引出 explicit 关键字 🍍多参构造函数 ✨为什么需要explicit关键字? ✨怎么使用explicit关键字? 四、总结 五…

npx\pnpm 镜像过期解决方法

. // 1. 清空缓存 npm cache clean --force // 2. 关闭SSL验证 npm config set strict-ssl false // 3. 安装 到这里就可以正常使用npm命令安装需要的工具了。如( npm install -g cnpm )

虚拟机中使用LNMP模拟跨域并结合前端代码解决CORS跨域的简单示例

目录 一、首先,下载lnmp_soft.tar.gz压缩包 二、解压lnmp_soft.tar.gz和下载相关的依赖,插件 三、修改/usr/local/nginx/conf/nginx.conf配置文件 四、/usr/local/nginx/sbin/nginx命令启动nginx 五、在/usr/local/nginx/html目录下新建80.html&…

书生·浦语大模型实战营之微调 Llama 3 实践与教程 (XTuner 版)

书生浦语大模型实战营之微调 Llama 3 实践与教程 (XTuner 版) Llama 3 近期重磅发布,发布了 8B 和 70B 参数量的模型,XTuner 团队对 Llama 3 微调进行了光速支持!!!开源同时社区中涌现了 Llama3-XTuner-CN 手把手教大家使用 XTuner 微调 Llama 3 模型。 XTuner:http:/…

图深度学习——2.图的理论知识

1.图 1.1 图的定义 图是由节点&#xff08;顶点&#xff09;和边构成的数学结构。图用于表示对象之间的关系&#xff0c;其中节点表示对象&#xff0c;边表示对象之间的关系。 一个图&#xff0c;记为 G <V, E> &#xff0c;它包括以下两个要素&#xff1a; 1.节点&am…

第22天:安全开发-PHP应用留言板功能超全局变量数据库操作第三方插件引用

第二十二天 一、PHP留言板前后端功能实现 开发环境&#xff1a; DW PHPStorm PhpStudy Navicat Premium DW : HTML&JS&CSS开发 PHPStorm : 专业PHP开发IDE PhpStudy &#xff1a;Apache MYSQL环境 Navicat Premium: 全能数据库管理工具 二、数据库创建&架…

机器学习(三)之监督学习2

前言&#xff1a; 本专栏一直在更新机器学习的内容&#xff0c;欢迎点赞收藏哦&#xff01; 笔者水平有限&#xff0c;文中掺杂着自己的理解和感悟&#xff0c;如果有错误之处还请指出&#xff0c;可以在评论区一起探讨&#xff01; 1.支持向量机&#xff08;Support Vector Ma…

iTwin Capture Modeler-23中文版下载地址及安装教程

文章目录 一、iTwin Capture Modeler23中文版安装教程二、iTwin Capture Modeler23中文版下载地址一、iTwin Capture Modeler23中文版安装教程 1. 解压安装包。订阅专栏(可获取专栏内所有文章阅读权限与软件安装包)后,从文末获取安装包解压,如下所示: 2. 右击安装包,选择以…

【Web】HNCTF 2022 题解(全)

目录 Week1 Interesting_include 2048 easy_html What is Web Interesting_http easy_upload Week2 ez_SSTI easy_include ez_ssrf Canyource easy_unser easy_sql ohmywordpress Week3 ssssti Fun_php ez_phar QAQ_1inclu4e logjjjjlogjjjj …

图像哈希:Global+Local

文章信息 作者&#xff1a;梁小平&#xff0c;唐振军期刊&#xff1a;ACM Trans. Multimedia Comput. Commun. Appl&#xff08;三区&#xff09;题目&#xff1a;Robust Hashing via Global and Local Invariant Features for Image Copy Detection 目的、实验步骤及结论 目…

内网隧道技术总结

隧道技术解决的是网络通信问题&#xff0c;因为在内网环境下&#xff0c;我们不同的内网主机管理员会进行不同的网络配置&#xff0c;我们就需要使用不同的方式去控制我们的内网主机。隧道技术是一个后渗透的过程&#xff0c;是可以是我们已经取得了一定的权限&#xff0c;在这…

NLP任务全览:涵盖各类NLP自然语言处理任务及其面临的挑战

自然语言处理(Natural Language Processing, 简称NLP&#xff09;是计算机科学与语言学中关注于计算机与人类语言间转换的领域。NLP将非结构化文本数据转换为有意义的见解&#xff0c;促进人与机器之间的无缝通信&#xff0c;使计算机能够理解、解释和生成人类语言。人类等主要…

(四)openlayers加入矢量图层.json文件

openlayers加入矢量图层.json文件 &#xff08;1&#xff09;接上一章节&#xff0c;添加矢量图层.json文件。首先下载.json矢量图层文件。链接&#xff1a;JSON矢量图层文件 &#xff08;2&#xff09;导入相关的依赖&#xff0c;提前把你下载好的矢量文件放入assets文件夹下…

巧用波卡生态优势,Mythical Games 引领 Web3 游戏新航向

Polkadot 对创新、安全和治理的承诺为 Mythical Games 提供了极大的发展价值。这个链上生态不仅将支持 Mythical Games 成长发展&#xff0c;还将帮助其他 Mythos 合作伙伴来壮大建设项目。 —— Mythical Games 创始人兼首席执行官 John Linden 近期 Web3 游戏行业又有新动向&…

microk8s拉取pause镜像卡住

前几天嫌服务器上镜像太多占空间&#xff0c;全部删掉了&#xff0c;今天看到 microk8s 更新了 1.30 版本&#xff0c;果断更新&#xff0c;结果集群跑不起来了。 先通过 microk8s.kubectl get pods --all-namespaces 命令看看 pod 状态。 如上图可以看到&#xff0c;所有的业…

JS -关于对象相关介绍

在JS中&#xff0c;除去基本的数据类型&#xff0c;还有包含对象这种复合数据类型&#xff0c;他可以储存多个键值对&#xff0c;并且每个键都是唯一的&#xff0c;并且在对象中可以包含各种数据类型的值&#xff0c;包括其他对象&#xff0c;数组&#xff0c;函数等。对象是Ja…