设计模式第二天|设计模式创建型:工厂模式、抽象工厂模式、单例模式、建造者模式

文章目录

  • 设计模式的分类
  • 工厂模式
    • 简单工厂
      • 定义
      • 核心
      • 俗话说
      • 优点
      • 缺点
      • 具体实现
    • 工厂模式(Spring IOC控制反转)
      • 定义
      • 核心
      • **组成**
      • **俗话说**
      • **实现思路**
      • **具体实现**
      • **使用场景**
  • 抽象工厂模式
    • **前提概念**
    • **定义**
    • **缺点**
    • **具体实现**
  • 单例模式
    • **定义**
    • **俗话说**
    • **特点**
    • **作用**
    • **分类**
    • **原理**
  • 建造者模式
    • 定义
    • **优点**
    • **缺点**
    • **角色组成**
    • 应用场景
    • 代码实现
    • 总结

设计模式的分类

总的来说设计模式分为三大类

  1. 创建型模式(五种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
  2. 结构型模式(七种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
  3. 行为型模式(十一种):策略模式,模板方法模式,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式。

这篇我们主要讲一下创建型模式。

由于我是java开发者,我会根据设计模式在java中的应用来说说。

工厂模式

简单工厂

定义

简单工厂模式其实并不算是一种设计模式,更多的时候是一种编程习惯。简单工厂的实现思路是,定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。

核心

为工厂类传入不同的type可以new不同的形状,返回结果为Shape 类型,这个就是简单工厂核心的地方了。

俗话说

现在有一个车间(工厂),由于需求比较少,所以一个车间可以生产不同的但是相像产品(具体对象),这些对象都是从一个模子里刻出来的(抽象对象)

优点

实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需知道具体产品类所对应的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点

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

具体实现

class ShapeFactory {public static Shape getShape(String type) {Shape shape = null;if (type.equalsIgnoreCase("circle")) {shape = new CircleShape();} else if (type.equalsIgnoreCase("rect")) {shape = new RectShape();} else if (type.equalsIgnoreCase("triangle")) {shape = new TriangleShape();}return shape;}}

工厂模式(Spring IOC控制反转)

工厂模式的作用就是创建对象

定义

工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。

核心

也就是说每个对象都有一个与之对应的工厂。

组成

  1. AbstractFactory(抽象工厂):声明了一组用于创建对象的方法,注意是一组。
  2. ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建对象的方法,生成一组具体对象。
  3. AbstractProduct(抽象产品):它为每种对象声明接口,在其中声明了对象所具有的业务方法。
  4. ConcreteProduct(具体产品):它定义具体工厂生产的具体对象。

俗话说

有好多车间,由于需求比较多,所以需要不同的车间来生产不同的商品,这些车间(具体工厂)生产的产品(具体对象)都是单一的,提高效率,这些车间都是一个车间模子(抽象工厂)里刻出来的,产品也是一个模子(抽象对象)里刻出来的.

实现思路

工厂方法的实现思路是,定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。

具体实现

就是将对象的具体创建交给工厂

  1. 产品类
//抽象产品
abstract class BMW {public BMW(){}
}
//具体产品
public class BMW320 extends BMW {public BMW320() {System.out.println("制造-->BMW320");}
}
//具体产品
public class BMW523 extends BMW{public BMW523(){System.out.println("制造-->BMW523");}
}
  1. 工厂类
//抽象工厂
interface FactoryBMW {BMW createBMW();
}
//具体工厂
public class FactoryBMW320 implements FactoryBMW{@Overridepublic BMW320 createBMW() {return new BMW320();}
}
//具体工厂
public class FactoryBMW523 implements FactoryBMW {@Overridepublic BMW523 createBMW() {return new BMW523();}
}
  1. 客户类(创建对象)
public class Customer {public static void main(String[] args) {FactoryBMW320 factoryBMW320 = new FactoryBMW320();BMW320 bmw320 = factoryBMW320.createBMW();FactoryBMW523 factoryBMW523 = new FactoryBMW523();BMW523 bmw523 = factoryBMW523.createBMW();}
}

使用场景

  1. 客户端不需要知道它所创建的对象的类
  2. 客户端可以通过子类来指定创建对应的对象。

抽象工厂模式

前提概念

  1. 产品等级结构

产品等级结构指的是产品的继承结构,例如一个空调抽象类,它有海尔空调、格力空调、美的空调等一系列的子类,那么这个空调抽象类和他的子类就构成了一个产品等级结构。

  1. 产品族

产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。比如,海尔工厂生产海尔空调、海尔冰箱,那么海尔空调则位于空调产品族中。

  1. 实体图
    在这里插入图片描述

定义

**抽象工厂模式主要用于创建相关对象的家族。**当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象

并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

缺点

在于添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

具体实现

  1. 产品类
//发动机以及型号  
public interface Engine {}  public class EngineA implements Engine{  public EngineA(){  System.out.println("制造-->EngineA");  }  
}  
public class EngineB implements Engine{  public EngineB(){  System.out.println("制造-->EngineB");  }  
}  //空调以及型号  
public interface Aircondition {} public class AirconditionA implements Aircondition{  public AirconditionA(){  System.out.println("制造-->AirconditionA");  }  
}  
public class AirconditionB implements Aircondition{  public AirconditionB(){  System.out.println("制造-->AirconditionB");  }  
} 
  1. 工厂类
//创建工厂的接口  
public interface AbstractFactory {  //制造发动机public Engine createEngine();//制造空调 public Aircondition createAircondition(); 
}  //为宝马320系列生产配件  
public class FactoryBMW320 implements AbstractFactory{ //发动机@Override  public Engine createEngine() {  //在这里新建一个对象return new EngineA();  }  //空调@Override  public Aircondition createAircondition() { //在这里新建一个对象return new AirconditionA();  }  
}  
//为宝马523系列胜场配件
public class FactoryBMW523 implements AbstractFactory {//发动机@Override  public Engine createEngine() {   //在这里新建一个对象return new EngineB();  }  //空调@Override  public Aircondition createAircondition() {  //在这里新建一个对象return new AirconditionB();  }  
} 
  1. 客户类
public class Customer {  public static void main(String[] args){  //生产宝马320系列配件//创建具体工厂对象FactoryBMW320 factoryBMW320 = new FactoryBMW320();  		//通过具体工厂对象创建同一族产品factoryBMW320.createEngine();factoryBMW320.createAircondition();//生产宝马523系列配件  FactoryBMW523 factoryBMW523 = new FactoryBMW523();  factoryBMW523.createEngine();factoryBMW523.createAircondition();}  
}
  1. 产品->工厂->客户使用

单例模式

定义

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

俗话说

类似与你的心脏,在你的身体里有且只有一个,无论怎么变化,它都是同一个对象。

特点

  1. 单例类只能有一个实例
  2. 单例类必须自己创建自己的唯一实例
  3. 单例类必须给所有其他对象提供这一实例

作用

单例模式就是为了避免不一致状态,避免政出多头。

分类

  1. 懒汉式(懒得自己动,靠别人调用)

在第一次调用的时候实例化自己

public class Singleton {private Singleton() {}private static Singleton single=null;//静态工厂方法(当第一次调用getInstance() 方法的时候自动创建对象)public static Singleton getInstance() {if (single == null) {  single = new Singleton();}  return single;}
}
  1. 饿汉式(饿得不行了,类刚加载的时候就自己实例化)

在类初始化时,已经自行实例化

public class Singleton1 {private Singleton1() {}//类初始化的时候就实例化对象,而不是调用方法才实例化private static final Singleton1 single = new Singleton1();//静态工厂方法 public static Singleton1 getInstance() {return single;}
}
  1. 线程安全的单例模式(进阶版:加了个线程同步)

在懒汉式单例模式基础上加上线程同步

原理

代码对静态方法 getInstance()进行同步,以确保多线程环境下只创建一个实例。如果getInstance()方法未被同步,并且线程A和线程B同时调用此方法,则执行if (instance == null)语句时都为真,那么线程A和线程B都会创建一个对象,在内存中就会出现两个对象,这样就违反了单例模式。而使用synchronized关键字进行同步后,则不会出现此种情况。

public class Singleton {                         private static Singleton instance = null;     // 私有构造方法,保证外界无法直接实例化。     private Singleton() {}                                   // 通过公有的静态方法获取对象实例     synchronized public static Singleton getInstace() {         if (instance == null) {                                 instance = new Singleton();         }                return instance;     }                                               
}

建造者模式

建造者模式是一种创建型设计模式,也叫生成器模式。

定义

封装一个复杂对象构造过程,并允许按步骤构造。

就是将复杂对象的创建过程拆分成多个简单对象的创建过程,并将这些简单对象组合起来构建出复杂对象。

建造者模式是一种对象创建型模式,它将构建复杂对象的过程和表示进行分离,使得同样的构建过程可以创建不同的表示。

优点

  1. 灵活:可以分步骤地构建复杂对象,使得构建过程更加灵活。
  2. 解耦:可以隔离复杂对象的创建和使用,客户端不必关心对象的创建细节。
  3. 易扩展:增加新的具体建造者很方便,可以扩展构建器功能,符合开闭原则。

缺点

  1. 增加工作量:需要额外的代码来创建和管理具体建造者类,增加了程序员的工作量。

  2. 效率低:相比于其他创建型模式,在运行时效率较低,特别是对象太复杂时。

角色组成

  1. 产品类(Product):表示被创建的复杂对象。它通常包含多个部分或者组成,并由具体的建造者逐步构建而成。
  2. 抽象建造者类(Builder):定义了建造复杂对象所需要的各个部分的创建方法。它通常包括多个构建方法和一个返回产品的方法。
  3. 具体建造者类(ConcreteBuilder):实现Builder接口,并提供各个部分或者组成的构建方法。
  4. 指挥者类(Director):负责控制建造者的构建顺序,指挥建造者如何构建复杂对象。

应用场景

  1. 生活场景
  • 盒饭套餐:顾客可以选择不同的菜,服务员按照顾客的要求,将这些菜组合起来,最终构建出一个完整的套餐。
  • 盖房子:需要分多个阶段进行,比如准备材料、打地基、盖围墙…。建造者模式可以将房屋的建造分解成多个步骤,每个步骤对应一个具体的建造者,最终由包工头(指导者)来调用不同的建造者,完成整个房子的建造。
  1. java场景
  • StringBuilder:能够动态地构建字符串。
  • Stream API:将集合类转为stream流,通过一系列的中间操作和终止操作来生成最终结果。
  • Lombok的@Builder注解:一个注解就可以生成建造者模式的代码。

代码实现

肯德徳都吃过吧,里面有很多的套餐。假设套餐主要由汉堡、薯条和饮料三种组成,每个组件都有不同种类和大小,并且每个套餐的组合方式也不同。下面以肯德徳套餐为例,解释建造者模式。

  1. 产品类:Meal
/*** 1.产品类(Product)*/
@Data
public class Meal {//汉堡包private String burger;//薯条private String fries;//饮料private String drink;
}
  1. 抽象建造者类:MealBuilder
/*** 2.抽象建造者(Builder)*/
public abstract class MealBuilder {protected Meal meal=new Meal();//构建汉堡public abstract void buildBurger();//构建薯条public abstract void buildFries();//构建饮料public abstract void buildDrink();public Meal getMeal(){return meal;}
}c
  1. 具体建造者类:BeefBurgerMealBuilder、ChickenMealBuilder、ShrimpMealBuilder
/*** 3.具体建造者(ConcreteBuilder):鸡肉汉堡套餐*/
public class ChickenMealBuilder extends MealBuilder{@Overridepublic void buildBurger() {meal.setBurger("鸡肉汉堡");}@Overridepublic void buildFries() {meal.setFries("中份薯条");}@Overridepublic void buildDrink() {meal.setDrink("大杯果汁");}
}/*** 3.具体建造者(ConcreteBuilder):牛肉汉堡套餐*/
public class BeefBurgerMealBuilder extends MealBuilder {@Overridepublic void buildBurger() {meal.setBurger("牛肉汉堡");}@Overridepublic void buildFries() {meal.setFries("大份薯条");}@Overridepublic void buildDrink() {meal.setDrink("中杯可乐");}
}/*** 3.具体建造者(ConcreteBuilder):虾肉汉堡套餐*/
public class ShrimpMealBuilder extends MealBuilder {@Overridepublic void buildBurger() {meal.setBurger("虾肉汉堡");}@Overridepublic void buildFries() {meal.setFries("小份薯条");}@Overridepublic void buildDrink() {meal.setDrink("大杯芬达");}
}
  1. 指挥者类:MealDirector
/*** 4.指导者(Director)*/
public class MealDirector {private MealBuilder mealBuilder;public void setMealBuilder(MealBuilder mealBuilder){this.mealBuilder=mealBuilder;}public Meal getMeal(){return mealBuilder.getMeal();}//制作套餐public void constructMeal(){mealBuilder.buildBurger();mealBuilder.buildFries();mealBuilder.buildDrink();}
}
  1. 测试
/*** 建造者模式测试类*/
@SpringBootTest
public class TestBuilder {@Testvoid testBuilder(){//创建指导者MealDirector director=new MealDirector();//执导建造牛肉套餐director.setMealBuilder(new BeefBurgerMealBuilder());director.constructMeal();Meal meal = director.getMeal();System.out.println("牛肉套餐:"+meal.toString());//鸡肉套餐director.setMealBuilder(new ChickenMealBuilder());director.constructMeal();Meal meal2 = director.getMeal();System.out.println("鸡肉套餐:"+meal2.toString());//虾肉套餐director.setMealBuilder(new ShrimpMealBuilder());director.constructMeal();Meal meal3 = director.getMeal();System.out.println("虾肉套餐:"+meal3.toString());}
}

总结

使用场景:

  1. 当需要创建一些特定的对象,但是它们拥有共同的组成部分时,比如:一个房子可以由个个部件:框架、墙、窗户等,这些部件可以组合起来构造完整的房子。
  2. 当对象的构建过程比较复杂且需要多个步骤时,例如,创建一份电子商务订单需要多个步骤,如选择商品、填写地址和支付等,这些步骤可以被分别封装成为订单构建器中的不同方法。
  3. 当需要创建一些特定类型的对象,例如复杂的数据结构或配置对象时,这在编写配置文件解析器以及通用数据结构如二叉树等时很有用。
  4. 建造者模式也可以被用于通过更高级的方式来构建复杂对象,例如:序列化和反序列化。

与抽象工厂模式的区别:

抽象工厂模式强调的是产品族的创建,即相关的产品一起被创建出来,而建造者模式强调的是一个复杂对象的创建,即它的各个部分逐步被创建出来。

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

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

相关文章

Django学习第一天(如何创建和运行app)

前置知识: URL组成部分详解: 一个url由以下几部分组成: scheme://host:port/path/?query-stringxxx#anchor scheme:代表的是访问的协议,一般为http或者ftp等 host:主机名,域名,…

《低代码指南》——Oracle APEX : AI在低代码开发中的创新应用

在低代码开发领域,我们正在目睹人工智能(AI)集成所带来的显著进展。Oracle公司最新推出的APEX 24.1版本,便是这一趋势的明显体现,其集成的AI功能旨在极大提高开发者的生产力,同时简化应用程序的创建过程。 Contents 将变革性的AI整合到低代码平台 将AI技术引入低代码平台…

二、BIO、NIO、直接内存与零拷贝

一、网络通信编程基础 1、Socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,是一组接口,由操作系统提供; Socket将复杂的TCP/IP协议处理和通信缓存管理都隐藏在接口后面,对用户来说就是使用简单的接口进行网络应用编程…

MySQL定时备份数据,并上传到oss

1.环境准备 1.安装阿里云的ossutil 2.安装mysql 2.编写脚本 脚本内容如下 #!/bin/bash # 数据库的配置信息,根据自己的情况进行填写 db_hostlocalhost db_usernameroot db_passwordroot db_namedb_root # oss 存贮数据的bucket地址 bucket_namerbsy-backup-buck…

SpringBoot:SpringBoot通过注解监测Controller接口

一、前言 在Spring Boot中,度量指标(Metrics)是监控和诊断应用性能与行为的重要工具。Spring Boot通过集成Micrometer和Spring Boot Actuator,提供了强大的度量指标收集与暴露功能。 二、度量指标 1. Micrometer Micrometer是一…

基于FPGA的以太网设计(2)----以太网的硬件架构(MAC+PHY)

1、概述 以太网的电路架构一般由MAC、PHY、变压器、RJ45和传输介质组成,示意图如下所示: 需要注意的是,上图是一个简化了的模型,它描述的是两台主机之间的直接连接,但在实际应用中基本都是多台主机构成的局域网,它们之间并不直接相连,而是通过交换机Switch来进行…

Linux云计算 |【第一阶段】SERVICES-DAY5

主要内容: 源码编译安装、rsync同步操作、inotify实时同步、数据库服务基础 实操前骤:(所需tools.tar.gz与users.sql) 1.两台主机设置SELinnx和关闭防火墙 setenforce 0 systemctl stop firewalld.service //停止防火墙 sy…

scss基本语法---嵌套、循环、条件(@for,@if),混入@mixin,继承@extend,导入@import,

scss是css预编译器,可以简化css代码的书写,并可以编译成css文件使用; 有关scss的安装使用可以参考:Sass语法---sass的安装和引用_引入sass-CSDN博客 嵌套、循环、条件(for,if) 嵌套 scss支持选择器的嵌套…

rk3568 OpenHarmony4.1 Launcher定制开发—桌面壁纸替换

Launcher 作为系统人机交互的首要入口,提供应用图标的显示、点击启动、卸载应用,并提供桌面布局设置以及最近任务管理等功能。本文将介绍如何使用Deveco Studio进行单独launcher定制开发、然后编译并下载到开发板,以通过Launcher修改桌面背景…

python一维表转二维表

一维表转二维表 import pandas as pd # 读取数据 product_df pd.read_csv(rD:\excelFile\practice\物品属性值一维表.csv,encodingutf-8) # print(product_df)# 将一维表转变二维 s pd.Series(list(product_df[属性值]),index[product_df[物品编号],product_df[属性名]]) …

TQSDRPI开发板教程:实现PL端的UDP回环与GPSDO

本教程将完成一个全面的UDP运行流程与GPSDO测试,从下载项目的源代码开始,通过编译过程,最终将项目部署到目标板卡上运行演示。此外,我们还介绍如何修改板卡的IP地址,以便更好地适应您的网络环境或项目需求。 首先从Gi…

使用nginx实现一个端口和ip访问多个vue前端

前言:由于安全组要求,前端页面只开放一个端口,但是项目有多个前端,此前一直使用的是一个前端使用单独一个端口进行访问,现在需要调整。 需要实现:这里以80端口为例,两个前端分别是:p…

Zabbix监控系统:zabbix服务部署+基于Proxy分布式部署+zabbix主动与被动监控模式

一、Zabbix概述 1.1 简介 zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 zabbix 能监视各种网络参数,保证服务器系统的安全运营,提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 zabbix…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(三)基变换与坐标变换;微分方程;李群和李代数;雅可比矩阵

一、基变换与坐标变换 字小,事不小。 因为第一反应:坐标咋变,坐标轴就咋变呀。事实却与我们想象的相反。这俩互为逆矩阵。 第一次读没有读明白,后面到事上才明白。 起因是多传感器标定:多传感器,就代表了多个坐标系,多个基底。激光雷达和imu标定。这个标定程序,网上,…

【VSCode】安装 【ESP-IDF】插件及【ESP32-S3】新建工程和工程配置

一、搭建基础工程 二、基础工程的文件架构解析 三、调试相关工具介绍 1、串口下载2、JTAG 下载与调试 四、工程的文件架构解析 五、基础工程配置 一、搭建基础工程 在 VS Code 中新建 ESP-IDF 基础工程的步骤如下: 1、启动 VS Code 并打开命令面板 按下“Ctrl…

1小时上手Alibaba Sentinel流控安全组件

微服务的雪崩效应 假如我们开发了一套分布式应用系统,前端应用分别向A/H/I/P四个服务发起调用请求: 但随着时间推移,假如服务 I 因为优化问题,导致需要 20 秒才能返回响应,这就必然会导致20秒内该请求线程会一直处于阻…

科研绘图系列:R语言TCGA分组饼图(multiple pie charts)

介绍 在诸如癌症基因组图谱(TCGA)等群体研究项目中,为了有效地表征和比较不同群体的属性分布,科研人员广泛采用饼图作为数据可视化的工具。饼图通过将一个完整的圆形划分为若干个扇形区域,每个扇形区域的面积大小直接对应其代表的属性在整体中的占比。这种图形化的展示方…

代码审计 | .NET SqlSugar框架注入漏洞

01阅读须知 此文所节选自小报童《.NET 代码审计》专栏,主要内容有涉及的.NET目录和文件操作、SQL注入方向的敏感函数、还有不安全的配置导致的漏洞挖掘思路,对.NET代码审计感兴趣的朋友们可以解锁该电子报刊,解锁更多的报刊内容。 02基本介…

【06】LLaMA-Factory微调大模型——微调模型评估

上文【05】LLaMA-Factory微调大模型——初尝微调模型,对LLama-3与Qwen-2进行了指令微调,本文则介绍如何对微调后的模型进行评估分析。 一、部署微调后的LLama-3模型 激活虚拟环境,打开LLaMA-Factory的webui页面 conda activate GLM cd LLa…

C# Program to print pyramid pattern (打印金字塔图案的程序)

编写程序打印由星星组成的金字塔图案 例子 : 输入:n 6输出: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 我们强烈建…