设计模式 - 创建型模式考点篇:工厂模式、建造者模式

目录

一、创建型模式

1.1、工厂模式

1.1.1、简单工厂模式(非 23 种经典设计模式)

概述

案例

1.1.2、静态工厂(扩展)

1.1.3、工厂方法模式

概念

案例

1.2、建造者模式

1.2.1、概念

1.2.2、案例

1.2.3、建造者模式扩展:链式编程底层

1.3、工厂方法模式 VS 建造者模式


一、创建型模式


1.1、工厂模式

1.1.1、简单工厂模式(非 23 种经典设计模式)

概述

简单工厂不是一种设计模式,反而比较像是一种编程习惯.

简单工厂包含一下角色:

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

案例

需求:设计一个咖啡店点餐系统.

思路:设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡 【LatteCoffee】);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。

以下代码为空架.

/*** 咖啡*/
public abstract class Coffee {public abstract String getName();public void addSugar() {System.out.println("加糖");}public void addWeight() {System.out.println("加量");}}
/*** 美式咖啡*/
public class AmericanCoffee extends Coffee{@Overridepublic String getName() {return "美式咖啡";}}
/*** 拿铁咖啡*/
public class LatteCoffee extends Coffee{@Overridepublic String getName() {return "拿铁咖啡";}}
/*** 咖啡店*/
public class CoffeeStore {public Coffee orderCoffee(String type) {//1.根据订单类型选取对应的咖啡Coffee coffee = null;if (type == null || type.equals("")) {throw new RuntimeException("type 非法");} else if (type.equals("ac")) {coffee = new AmericanCoffee();} else if(type.equals("lc")) {coffee = new LatteCoffee();} else {throw new RuntimeException("type 非法");}//2.加糖加量coffee.addSugar();coffee.addWeight();return coffee;}}
/*** 测试客户端*/
public class ClientCoffee {public static void main(String[] args) {CoffeeStore store = new CoffeeStore();Coffee coffee = store.orderCoffee("ac");System.out.println(coffee.getName());}}

可以产出上述代码中 Coffee 类为抽象产品,AmericanCoffee 和 LatteCoffee 为具体产品,但是没有抽象工厂.  以下使用 简单工厂模式 对上述代码进行改造.

public abstract class Coffee {public abstract String getName();public void addSugar() {System.out.println("加糖");}public void addWeight() {System.out.println("加量");}}
public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}}
public class LatteCoffee extends Coffee {@Overridepublic String getName() {return "拿铁咖啡";}}
/*** 简单工厂模式*/
public class SimpleCoffeeFactory {public Coffee createCoffee(String type) {//1.根据订单类型选取对应的咖啡Coffee coffee = null;if (type == null || type.equals("")) {throw new RuntimeException("type 非法");} else if (type.equals("ac")) {coffee = new AmericanCoffee();} else if(type.equals("lc")) {coffee = new LatteCoffee();} else {throw new RuntimeException("type 非法");}//2.加糖加量coffee.addSugar();coffee.addWeight();return coffee;}}
public class CoffeeStore {public Coffee orderCoffee(String type) {//1.让工厂来创建对象SimpleCoffeeFactory factory = new SimpleCoffeeFactory();Coffee coffee = factory.createCoffee(type);//2.加料coffee.addWeight();coffee.addSugar();return coffee;}}
public class ClientCoffee {public static void main(String[] args) {CoffeeStore store = new CoffeeStore();Coffee coffee = store.orderCoffee("ac");System.out.println(coffee.getName());}}

上述代码中有了 SimpleCoffeeFactory ,使得 Coffee 的具体实现类和 CoffeeStore 解耦合,但是又产生了 CoffeeStore 和 SimpleCoffeeFactory 对象的耦合. 后期我们如果要加新的咖啡品种,势必需要修改 SimpleCoffeeFactory 的代码,违反了开闭原则.

优点:

解耦合:将对象的创建和业务逻辑层分开,避免将来修改客户端代码.  入股偶要实现新产品,直接修改工厂类,不需要再原客户端代码,更容易扩展.

缺点:

违背“开闭原则”:增加新产品时还需要修改工厂类代码.

1.1.2、静态工厂(扩展)

在实际的开发中也有一部分人将工厂类中的创建对象的功能定义为静态的,这个就是静态工厂模式,避免对象的重复创建.  他也不是属于 23 中设计模式中的.

/*** 简单工厂模式*/
public class StaticCoffeeFactory {public static Coffee createCoffee(String type) {//1.根据订单类型选取对应的咖啡Coffee coffee = null;if (type == null || type.equals("")) {throw new RuntimeException("type 非法");} else if (type.equals("ac")) {coffee = new AmericanCoffee();} else if(type.equals("lc")) {coffee = new LatteCoffee();} else {throw new RuntimeException("type 非法");}//2.加糖加量coffee.addSugar();coffee.addWeight();return coffee;}}

1.1.3、工厂方法模式

概念

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。

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

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

需求:设计一个咖啡店点餐系统,咖啡种类有美式咖啡和拿铁咖啡.

/*** 抽象产品: 咖啡类*/
public abstract class Coffee {public abstract String getName();public void addSugar() {System.out.println("加糖");}public void addWeight() {System.out.println("加量");}}
/*** 具体产品:美式咖啡类*/
public class AmericanCoffee extends Coffee {@Overridepublic String getName() {return "美式咖啡";}}
/*** 具体产品:拿铁咖啡类*/
public class LatteCoffee extends Coffee {@Overridepublic String getName() {return "拿铁咖啡";}}
/*** 抽象工厂: 咖啡工厂*/
public interface CoffeeFactory {Coffee createCoffee();}
/*** 具体工厂:美式咖啡工厂*/
public class AmericanCoffeeFactory implements CoffeeFactory{@Overridepublic Coffee createCoffee() {return new AmericanCoffee();}}
/*** 具体工厂:拿铁咖啡工厂*/
public class LatteCoffeeFactory implements CoffeeFactory{@Overridepublic Coffee createCoffee() {return new LatteCoffee();}}
/*** 咖啡商店*/
public class CoffeeStore {private CoffeeFactory factory;public void setFactory(CoffeeFactory factory) {this.factory = factory;}public Coffee orderCoffee() {//1.创建咖啡对象Coffee coffee = factory.createCoffee();//2.加料coffee.addWeight();coffee.addSugar();return coffee;}}
public class ClientCoffee {public static void main(String[] args) {CoffeeStore store = new CoffeeStore();
//        AmericanCoffeeFactory factory = new AmericanCoffeeFactory();LatteCoffeeFactory factory = new LatteCoffeeFactory();store.setFactory(factory);Coffee coffee = store.orderCoffee();System.out.println(coffee.getName());}}

优点:

使用便利:用户只需要知道具体的工厂名称就可以拿到产品,无须知道产品的具体创建过程.

满足“开闭原则”:当需要添加新的产品时,无需对原工厂进行修改,只需要添加具体的产品类和工厂即可.

缺点:

“类爆炸”:每增加一个产品就需要增加一个具体产品类和一个对应的具体工厂类,增加系统复杂度.

使用场景:

  • 重复代码 : 创建对象需要使用大量重复的代码 ;
  • 不关心创建过程 : 客户端 不依赖 产品类 , 不关心 实例 如何被创建 , 实现等细节 ;
  • 创建对象 : 一个类通过其子类来指定创建哪个对象 ;

1.2、建造者模式

1.2.1、概念

将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。例如电脑的主机由 cpu、内存、主板、显卡 构成,用户只需要指定主机的类型就可以得到相应的主机,无需知道内部的具体构造细节.

建造者模式包含如下角色:

  • 抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。
  • 具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体 创建方法。在构造过程完成后,提供产品的实例。
  • 产品类(Product):要创建的复杂对象。
  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产 品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

1.2.2、案例

生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质 的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。

/*** 产品类:自行车类*/
public class Bike {//车架private String frame;//车座private String seat;public String getFrame() {return frame;}public void setFrame(String frame) {this.frame = frame;}public String getSeat() {return seat;}public void setSeat(String seat) {this.seat = seat;}}
/*** 抽象建造者类*/
public abstract class Builder {//这里只是一个空架子,还需要具体实现protected Bike bike = new Bike();//自行车的组成部分public abstract void buildFrame();public abstract void buildSeat();//构建自行车public abstract Bike createBike();}
/*** 具体建造者类:捷安特建造者类*/
public class GiantBuilder extends Builder{@Overridepublic void buildFrame() {this.bike.setFrame("碳纤维车架");}@Overridepublic void buildSeat() {this.bike.setSeat("橡胶车座");}@Overridepublic Bike createBike() {return this.bike;}}
/*** 具体建造者类:摩拜建造者类*/
public class MobikeBuilder extends Builder {@Overridepublic void buildFrame() {this.bike.setFrame("铝合金车架");}@Overridepublic void buildSeat() {this.bike.setSeat("真皮车座");}@Overridepublic Bike createBike() {return this.bike;}}
/*** 指挥者类*/
public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}/*** 指导构造* @return*/public Bike construct() {//开始构建builder.buildFrame();builder.buildSeat();return builder.createBike();}}
/*** 测试类*/
public class Client {public static void main(String[] args) {//建造捷安特自行车showBike(new GiantBuilder());//建造摩拜自行车showBike(new MobikeBuilder());}private static void showBike(Builder builder) {Director director = new Director(builder);Bike bike = director.construct();System.out.println(bike.getFrame());System.out.println(bike.getSeat());}}

优点:

解耦合:客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得 相同的创建过程可以创建不同的产品对象。

易扩展,符合开闭原则:如果有新的需求,通过实现一个新的建造者就可以完成,基本上不用修改其他代码.

缺点:

如果产品之间的差异性比较大,则不适合使用,因此使用范围受到一定的限制.

使用场景:

创建对象的过程比较负责,由多个部件构成,但构建的顺序是稳定的.

产品的构建过程和最终的表示是独立的.

1.2.3、建造者模式扩展:链式编程底层

建造者模式除了上述用途以外,在开发中还有一种常用的使用方式,就是当一个类构造器需要传入多个参数,此时创建这个类的实例,代码的可读性就会非常差,而且很容易引入新的错误. 此时就可以使用 链式编程底层 的方式对 建造者模式进行重构.

 重构后代码如下:

public class Phone {private String cpu;private String screen;private String memory;private String mainBoard;//私有构造,只对内提供private Phone(Builder builder) {this.cpu = builder.cpu;this.screen = builder.screen;this.memory = builder.memory;this.mainBoard = builder.mainBoard;}@Overridepublic String toString() {return "Phone{" +"cpu='" + cpu + '\'' +", screen='" + screen + '\'' +", memory='" + memory + '\'' +", mainBoard='" + mainBoard + '\'' +'}';}//链式编程构建public static class Builder {private String cpu;private String screen;private String memory;private String mainBoard;public Builder cpu(String cpu) {this.cpu = cpu;return this;}public Builder screen(String screen) {this.screen = screen;return this;}public Builder memory(String memory) {this.memory = memory;return this;}public Builder mainBoard(String mainBoard) {this.mainBoard = mainBoard;return this;}public Phone build() {return new Phone(this);}}}
public class Client {public static void main(String[] args) {Phone phone = new Phone.Builder().cpu("intel").screen("三星屏幕").mainBoard("华硕").memory("金士顿").build();System.out.println(phone);}}

重构后使用起来更加方便,提高开发效率.  但是从软件设计上,对程序员的要求比较高.

1.3、工厂方法模式 VS 建造者模式

工厂方法模式注重是整体对象的创建方式;而建造者模式注重的是部件一步一步的创建出一个复杂对象的过程 .

比如我要制造一个超人,如果使用工厂方法模式,直接产生出来就是一个力大无穷、能飞,内裤外穿的超人;而如果使用建造者模式,则需要组装 手、头、脚、躯干、裤头... 一个超人就诞生了.

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

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

相关文章

vue3使用知识点总结

一、vue3 项目搭建 npm 6.x npm init vitelatest myvue3 --template vuevue 3.2.26使用 element plus ui 框架 npm i -S element plus//全部引入 import ElementPlus from element-plus; import element-plus/dist/index.css; const Vue createApp(App); Vue.use(ElementPl…

腾讯会议录制没有声音?看完这篇你就懂了

“腾讯会议录制的视频怎么没有声音呀?老师用腾讯会议上网课,就想用腾讯会议内置的录屏功能录下来,可是录制的视频没有声音!真的服了,有没有人知道怎么解决的,帮帮忙。” 腾讯会议是一种常用的远程会议工具…

基于遗传算法的新能源电动汽车充电桩与路径选择(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

iTOP-RK3588开发板使用 tensorflow框架

TensorFlow 是一个软件库或框架,由 Google 团队设计,以最简单的方式实现机器学习和深度学习概念。它结合了优化技术的计算代数,便于计算许多数学表达式。TensorFlow 有以下 重要功能 - 它包含一个叫做张量概念,用来创建多维数组&…

【密评】商用密码应用安全性评估从业人员考核题库(五)

商用密码应用安全性评估从业人员考核题库(五) 国密局给的参考题库5000道只是基础题,后续更新完5000还会继续更其他高质量题库,持续学习,共同进步。 1001 单项选择题 下列分组密码认证模式中,使用密钥最少的…

深入浅出DAX:购买推荐及产品ABC分类分析

深入浅出DAX:购买推荐及产品ABC分类分析 DAX运算求值的三步骤。首先是检测筛选,然后将筛选功能应用于基础表格,最后计算结果。DAX中的筛选器函数是复杂且功能强大的函数。例如筛选函数可用于操作数据上下文来创建动态计算。 01、使用细节说…

Spring Boot如何配置CORS支持

Spring Boot如何配置CORS支持 CORS(跨源资源共享)是一种Web浏览器的安全性功能,用于控制网页上的脚本文件从不同的源加载其他网页资源。在开发现代Web应用程序时,通常需要跨域请求不同的资源,如API服务或其他Web应用程…

前端系列-1 HTML+JS+CSS基础

背景: 前端系列会收集碎片化的前端知识点,作为自己工作和学习时的字典,欢迎读者收藏和使用。 笔者是后端开发😶前端涉猎不深,因此文章重在广度和实用,对原理和性能不会过多深究。 1.html 1.1 html5网页结…

嵌入式处理趋势,第一部分:超集成MCU

当今的嵌入式微控制器(MCU)是协同和创新的惊人例子。单个芯片上可容纳30,000至2百万个门,直到最近,各种集成的组件和模块都被视为独立的高级IC。 例如,当前典型的MCU设备(下面的图1)可能包含以…

Quarto 入门教程 (1):简单介绍和资料汇总

本推文是 “手把手教你使用 Quarto 构建文档” 教程的第一部分,本文先介绍 Quarto 构建文档的原理;可创建的文档类型;对应的参考资源分享。 下一部分,会手把手介绍如何使用它(下次推文吧~)。 …

Springboot使用Aop保存接口请求日志到mysql(及解决Interceptor拦截器中引用mapper和service为null)

一、Springboot使用Aop保存接口请求日志到mysql 1、添加aop依赖 <!-- aop日志 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency> 2、新建接口保存数据…

排序算法之【归并排序】

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

chrome窗口

chrome 窗口的层次&#xff1a; 父窗口类名&#xff1a;Chrome_WidgetWin_1 有两个子窗口&#xff1a; Chrome_RenderWidgetHostHWNDIntermediate D3D Window // 用于匹配 Chrome 窗口的窗口类的前缀。 onst wchar_t kChromeWindowClassPrefix[] L"Chrome_WidgetWin_…

《低代码指南》——低代码维格云服务菜单

简介​ 快速了解付费客户能够获得维格服务团队哪些服务,本篇内容不包含使用免费试用版本的客户。 了解维格表产品价格与功能权益:戳我看价格与权益​ 客户付费后能得到哪些服务项目?​ 常规服务项目:

一、Excel VBA 是个啥?

Excel VBA 从入门到出门一、Excel VBA 是个啥&#xff1f;二、Excel VBA 简单使用 &#x1f44b;Excel VBA 是个啥&#xff1f; ⚽️1. Excel 中的 VBA 是什么&#xff1f;⚽️2. 为什么 VBA 很重要&#xff1f;⚽️3. 是否有无代码方法可以在 Excel 中实现工作流程自动化&…

深挖 Python 元组 pt.1

哈喽大家好&#xff0c;我是咸鱼 好久不见甚是想念&#xff0c;2023 年最后一次法定节假日已经结束了&#xff0c;不知道各位小伙伴是不是跟咸鱼一样今天就开始“搬砖”了呢&#xff1f; 我们知道元组&#xff08;tuple&#xff09;是 Python 的内置数据类型&#xff0c;tupl…

Qt扫盲-QTreeView 理论总结

QTreeView 理论使用总结 一、概述二、快捷键绑定三、提高性能四、简单实例1. 设计与概念2. TreeItem类定义3. TreeItem类的实现4. TreeModel类定义5. TreeModel类实现6. 在模型中设置数据 一、概述 QTreeView实现了 model 中item的树形表示。这个类用于提供标准的层次列表&…

C#封装、继承和多态的用法详解

大家好&#xff0c;今天我们将来详细探讨一下C#中封装、继承和多态的用法。作为C#的三大面向对象的特性&#xff0c;这些概念对于程序员来说非常重要&#xff0c;因此我们将对每个特性进行详细的说明&#xff0c;并提供相应的示例代码。 目录 1. 封装&#xff08;Encapsulati…

【用unity实现100个游戏之14】Unity2d做一个建造与防御类rts游戏

前言 欢迎来到本次教程&#xff0c;我将为您讲解如何使用 Unity 引擎来开发一个建造与防御类 RTS&#xff08;即实时战略&#xff09;游戏。 在本教程中&#xff0c;我们将学习如何创建 2D 场景、设计 2D 精灵、制作 2D 动画、响应用户输入、管理游戏数据、以及其他有关游戏开…

机器学习7:pytorch的逻辑回归

一、说明 逻辑回归模型是处理分类问题的最常见机器学习模型之一。二项式逻辑回归只是逻辑回归模型的一种类型。它指的是两个变量的分类&#xff0c;其中概率用于确定二元结果&#xff0c;因此“二项式”中的“bi”。结果为真或假 — 0 或 1。 二项式逻辑回归的一个例子是预测人…