23种设计模式之创建型模式篇

一、创建型模式

这类模式主要关注对象的创建过程。它们试图在创建对象的同时,将对象的创建和使用分离,以达到更高的灵活性和可扩展性.

包括:
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)
  • 单例模式(Singleton)
  • 建造者模式(Builder)
  • 原型模式(Prototype)
1、工厂方法模式(Factory Method)
1.1.代码实现
//操作步骤一:定义一个动物类接口
public interface Animal {void speak();
}//操作步骤二:Cat实现动物类接口
public class Cat implements Animal {@Overridepublic void speak() {System.out.println("我是cat类,喵喵喵");}
}//操作步骤二:Dog实现动物类接口
public class Dog implements Animal {@Overridepublic void speak() {System.out.println("我是dog类,汪汪汪");}
}//操作步骤三:工厂类
public class AnimalFactory {/*** 创建一个动物,根据类型创建* */public static Animal createAnimal(String type){if (type.equalsIgnoreCase("dog")) {return new Dog();} else if (type.equalsIgnoreCase("cat")) {return new Cat();} else {throw new IllegalArgumentException("Invalid animal type");}}}//代码测试
public class FactoryTest {/*** 1.定义了一个Animal接口和两个实现该接口的类Dog和Cat。* 2.创建了一个工厂类AnimalFactory,它有一个静态方法createAnimal,该方法根据传入的类型参数来创建相应的					动物对象。* 3.在客户端代码中,我们使用工厂类来创建不同的动物对象并调用它们的speak方法。** 这个例子展示了工厂模式的基本用法,通过工厂类来创建对象,而不是直接使用构造函数。* 这样做的好处是可以将对象的创建逻辑与使用逻辑分离,使得代码更加灵活和可维护。* */public static void main(String[] args) {Animal cat = AnimalFactory.createAnimal("cat");cat.speak();        //创建一个cat类Animal dog = AnimalFactory.createAnimal("dog");dog.speak();}
}
1.2.概念总结
1.2.1.工厂模式主要有以下几种类型:

1.简单工厂模式2.工厂方法模式 3.抽象工厂模式

1.2.2.使用场景:
  1. 创建复杂对象:如果一个对象的创建过程非常复杂,需要很多步骤,工厂模式可以将这些步骤封装在工厂类中,简化客户端代码。

  2. 对象类型动态决定:如果需要在运行时根据不同的情况创建不同的对象,可以使用工厂模式。例如,根据用户输入的信息创建不同类型的图形对象。

  3. 依赖注入:在依赖注入的应用中,工厂模式可以用来创建所需的依赖对象,并将其注入到目标对象中。

  4. 多数据库支持:如果应用需要支持多种数据库,可以使用工厂模式来创建对应的数据库连接对象。

  5. 工具类创建:如果一个类无法轻易通过new直接创建(例如,由于某些原因需要隐藏其构造函数),可以提供一个静态工厂方法来创建该类的实例。

  6. 遵循开闭原则:工厂模式允许系统在不修改现有代码的情况下引入新的产品类,这有助于保持系统的灵活性和可扩展性。

  7. 配置文件加载:在读取配置文件并根据配置信息创建相应对象时,工厂模式非常有用。

  8. 多平台或多环境支持:针对不同的平台或环境可能需要创建不同的对象,工厂模式可以根据环境变量或平台特性来决定实例化哪个类。

  9. 游戏开发中的实体生成:在游戏开发中,不同的游戏实体(如角色、道具、敌人等)可以通过工厂模式来创建,便于管理和扩展。

10.框架和库的开发:在设计框架或库时,为了提供灵活的扩展点,通常会使用工厂模式来创建关键组件。

总体来说,工厂模式适用于那些对象创建过程复杂、需要隔离创建和使用、或者需要对创建过程进行集中管理的场景。
通过使用工厂模式,可以提高代码的模块化和可维护性,同时减少出错的可能性。

2、单例模式(Singleton)
2.1.代码实现
/*** @author :jerry* @date :Created in 2024/4/19 13:50* @description:枚举实现单利模式* @version: V1.1*/
public enum SingletonEnum {INSTANCE;// 在枚举中定义实例变量和方法private String name;public void setName(String name) {this.name = name;}public String getName() {return name;}//代码测试public static void main(String[] args) {// 获取单例对象并设置名称SingletonEnum singleton = SingletonEnum.INSTANCE;singleton.setName("Singleton");// 输出单例对象的名称System.out.println(singleton.getName());}
}/*** @author :jerry* @date :Created in 2024/4/19 13:59* @description:饿汉式(线程安全):* @version: V1.1*/
public class EagerSingleton {//类加载时就创建实例private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}public static void main(String[] args) {// 获取单例对象EagerSingleton instanceObj = EagerSingleton.getInstance();System.out.println("其他操作");}
}/*** @author :jerry* @date :Created in 2024/4/19 13:59* @description:懒汉式(线程不安全):* @version: V1.1*/
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {//第一次使用时创建实例,实现了延迟加载if (instance == null) {instance = new LazySingleton();}return instance;}public static void main(String[] args) {LazySingleton instanceObj = LazySingleton.getInstance();System.out.println("其他操作");}
}/*** @author :jerry* @date :Created in 2024/4/19 14:16* @description:双重检查锁定* @version: V1.1*/
public class SingletonDouble {private static volatile SingletonDouble instance;private SingletonDouble() {}public static SingletonDouble getInstance() {if (instance == null) {synchronized (SingletonDouble.class) {if (instance == null) {instance = new SingletonDouble();}}}return instance;}public static void main(String[] args) {SingletonDouble instance = SingletonDouble.getInstance();System.out.println("其他业务代码");}
}
2.2.概念总结

单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,并提供该实例的全局访问点。

2.2.1.概念

单例模式的核心思想是控制对象的创建,确保一个类在任何情况下都只有一个实例存在。这个唯一的实例可以通过特定的方法在整个应用程序中被访问。

2.2.2.优点

单例模式可以节省系统资源,对于频繁使用的对象,避免多次创建和销毁;同时,它还提供了一个对资源的受控访问点,比如配置文件、线程池或数据库连接等。

2.2.3.实现方式
  • 饿汉式:在类加载时就创建实例,可能导致资源浪费,但简单且能保证线程安全。
  • 懒汉式:在第一次使用时创建实例,实现了延迟加载,但需要考虑线程安全问题。
  • 双重检查锁定:结合了懒汉式的延迟加载和线程安全的优点,通过同步锁和两次检查来确保只创建一个实例。
  • 静态内部类:利用类加载机制保证初始化实例时的线程安全和懒加载。
  • 枚举:通过枚举类型实现单例,自动支持序列化机制,绝对防止多次实例化。
  • C++11 std::call_once:提供了一次性调用的功能,确保某个函数只被执行一次,适用于C++中的单例实现。
2.2.4.问题和注意事项:
  • 线程安全:在多线程环境下,需要确保单例的创建不会发生并发问题。
  • 延迟加载:在某些实现中,单例的实例是在第一次使用时才创建的,这可以减少程序启动时的资源消耗。
  • 反序列化:在Java中,单例对象在序列化和反序列化过程中可能会被破坏,需要注意避免这种情况的发生。

总的来说,单例模式适用于那些需要频繁使用且不需要多个实例的场景,如配置管理、日志记录、驱动程序对象等。它可以减少系统开销,但同时也需要注意其可能带来的问题,如内存泄漏和过度使用导致的代码耦合。在实际使用中,应根据具体情况选择合适的实现方法,并注意单例的生命周期管理和访问控制。

3、抽象工厂模式(Abstract Factory)
3.1.代码实现
//操作步骤一:抽象工厂
public interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}//操作步骤二:抽象产品A
public interface ProductA {void operationA();
}//操作步骤三:抽象产品B
public interface ProductB {void operationB();
}//操作步骤四:具体产品A1
public class ConcreteProductA1 implements ProductA {@Overridepublic void operationA() {System.out.println("ConcreteProductA1 operationA");}
}
//操作步骤四:具体产品A2
public class ConcreteProductA2 implements ProductA {@Overridepublic void operationA() {System.out.println("ConcreteProductA2 operationA");}
}
//操作步骤四:具体产品B1
public class ConcreteProductB1 implements ProductB {@Overridepublic void operationB() {System.out.println("ConcreteProductB1 operationB");}
}
//操作步骤四:具体产品B2
public class ConcreteProductB2 implements ProductB {@Overridepublic void operationB() {System.out.println("ConcreteProductB2 operationB");}
}
//操作步骤五:具体工厂1
public class ConcreteFactory1 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA1();}@Overridepublic ProductB createProductB() {return new ConcreteProductB1();}
}//操作步骤五:具体工厂2
public class ConcreteFactory2 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA2();}@Overridepublic ProductB createProductB() {return new ConcreteProductB2();}
}public class AbstractFactoryTest {/***1.ProductA和ProductB是抽象产品接口,分别定义了各自的操作方法。* ConcreteProductA1、ConcreteProductA2、ConcreteProductB1和ConcreteProductB2是具体的产品类,实现了相应的抽象产品接口。* 2.AbstractFactory是抽象工厂接口,定义了创建产品的方法。ConcreteFactory1和ConcreteFactory2是具体的工厂类,实现了抽象工厂接口,并返回相应的具体产品对象。* 在客户端代码中,通过调用不同的工厂对象的创建方法来获取不同类型的产品对象,并执行相应的操作* */public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();ProductA productA1 = factory1.createProductA();ProductB productB1 = factory1.createProductB();productA1.operationA(); // 输出:ConcreteProductA1 operationAproductB1.operationB(); // 输出:ConcreteProductB1 operationBAbstractFactory factory2 = new ConcreteFactory2();ProductA productA2 = factory2.createProductA();ProductB productB2 = factory2.createProductB();productA2.operationA(); // 输出:ConcreteProductA2 operationAproductB2.operationB(); // 输出:ConcreteProductB2 operationB}
}
3.2.概念总结

抽象工厂模式是一种创建型设计模式,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。

3.2.1.这种模式通常用于以下几种情况:
  • 产品族和产品等级结构:当需要创建多个产品族的产品时,每个产品族都有其自身的等级结构。
  • 跨产品族的共享约束:如果不同产品族之间存在一些共同的约束或配置,可以使用抽象工厂来简化这些约束的管理。
  • 产品的复杂创建过程:如果产品的创建过程涉及到多个步骤或者需要多个组件,抽象工厂可以帮助将这个过程封装起来,使得客户端代码不需要知道具体的创建细节。

在实际应用中,抽象工厂模式可以帮助我们实现高度模块化和可扩展的设计,例如在开发家具商店模拟器时,可以通过抽象工厂模式来创建不同类型的家具产品,如椅子、桌子等,而无需在客户端代码中指定具体的产品类型。

4、建造者模式(Builder)
4.1.代码实现
//操作步骤一:抽象建造者角色
public interface Builder {void buildPartA();void buildPartB();
}//操作步骤二:产品角色
public class Product {private String partA;private String partB;public void setPartA(String partA) {this.partA = partA;}public void setPartB(String partB) {this.partB = partB;}public void show() {System.out.println("PartA: " + partA + ", PartB: " + partB);}
}//操作步骤三:指挥者角色
public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}public void construct() {builder.buildPartA();builder.buildPartB();}public Product getResult() {return ((ConcreteBuilder) builder).getResult();}
}//操作步骤四:具体建造者角色
public class ConcreteBuilder implements Builder {private Product product = new Product();public void buildPartA() {product.setPartA("Part A");}public void buildPartB() {product.setPartB("Part B");}public Product getResult() {return product;}
}//测试代码
public class BuilderTest {/***Product类代表了要创建的复杂对象,Builder接口定义了构建产品各个部分的抽象接口,* ConcreteBuilder类实现了Builder接口并完成了产品的各个部分的构建* ,而Director类则负责指挥ConcreteBuilder进行产品的构建。*** 客户端代码通过创建ConcreteBuilder和Director对象,并调用指挥者的construct方法来构建最终的产品。* */public static void main(String[] args) {Builder builder = new ConcreteBuilder();Director director = new Director(builder);director.construct();Product product = director.getResult();product.show();}
}
4.2.概念总结

建造者模式(Builder)是一种对象创建型设计模式,旨在将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

4.2.1.建造者模式的关键角色和组件包括:
  • 产品(Product):表示要创建的复杂对象。
  • 抽象建造者(Builder):定义创建产品各个部分的抽象接口。
  • 具体建造者(ConcreteBuilder):实现抽象建造者接口,完成产品的各个部分的构建。
  • 指挥者(Director):负责构建产品的对象,指挥具体建造者进行产品的构建。
5、原型模式(Prototype)
5.1.代码实现
//操作步骤一:定义一个抽象原型类
public class Prototype implements Cloneable {private String value;public Prototype(String value) {this.value = value;}// 覆盖clone方法@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}public String getValue() {return value;}public void setValue(String value) {this.value = value;}
}//测试代码
public class PrototypeTest {/*** Prototype类实现了Cloneable接口并覆盖了clone()方法。** 在main方法中,我们创建了一个原始对象,并通过调用clone()方法得到了一个复制的对象。这样我们就实现了原型模式。* */public static void main(String[] args) throws CloneNotSupportedException {Prototype prototype1 = new Prototype("Tom");Prototype prototype2 = (Prototype) prototype1.clone();System.out.println("prototype1: " + prototype1.getValue());System.out.println("prototype2: " + prototype2.getValue());}
}
5.2.概念总结

原型模式是一种创建型设计模式,用于通过复制现有的实例来创建新的对象,而不是通过调用构造函数来新建对象。

原型模式的关键在于利用已有的实例作为模板来创建新的实例,这样可以在不知晓具体类的情况下生成新对象。这种模式适用于那些创建成本高或者需要重复使用相似对象的场合。以下是原型模式的一些关键点:

  • 结构与实现:原型模式通常涉及到一个原型接口,该接口定义了克隆自身的方法。具体的原型类实现这个接口,并提供深克隆和浅克隆两种实现方式。
  • 深克隆与浅克隆:深克隆会复制对象以及所有嵌套引用的对象,而浅克隆只复制对象本身和它的引用,不复制引用的对象。两者的选择取决于具体的应用场景。
  • 优缺点:原型模式的优点在于可以在运行时动态地创建对象,不需要知道具体的类名。同时,它还能保持原有对象的状态,使得复制更为便捷。然而,其主要缺点是每个子类都需要实现克隆方法,这可能导致代码的复杂性增加。
  • 使用场景:当直接创建对象的成本比复制一个已有对象更高时,或者当希望获得对一个复杂对象的独立副本时,原型模式是一个很好的选择。例如,在使用像Photoshop这样的图形编辑软件时,用户可以通过复制图层来重用和修改图像部分,而不需要从头开始创建新图层。

综上所述,原型模式提供了一种灵活且高效的方式来创建对象,尤其适合那些对象创建成本较高或者需要避免与原始对象共享状态的场景。在实际应用中,根据具体需求选择合适的克隆方法(深克隆或浅克隆)是实现原型模式的关键。

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

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

相关文章

C# 反射基础

1 在.NET中程序集是什么? 程序集(Assembly)以可执行文件(.exe)或动态链接库文件(.dll)的形式存在,是.NET应用程序构建的基本单元。程序集可用于部署、版本控制和设置安全权限等。 2.程序集的有哪些部分组成? 程序集…

Unity UGUI透明区域点击无效

是这样的&#xff0c;我有一张图&#xff0c;客户给的是1920*1080&#xff0c;但只有中间部分是按钮&#xff0c;是有效像素。为了让空白区域点击无效。需要设置如下 并且加上下面这句 this.GetComponent<Image>().alphaHitTestMinimumThreshold 0.1f;

tomcat中Pipeline-Valve解析

tomcat中用到Pipeline-Value有二种方式&#xff0c;一种是管道/阀门&#xff0c;另一种是过滤器链/过滤器。 管道/阀门过滤器链/过滤器管道&#xff08;Pipeline&#xff09;过滤器链&#xff08;FilterChain&#xff09;阀门&#xff08;Valve&#xff09;过滤器&#xff08;…

python学习笔记B-08:序列结构之列表--列表的遍历操作

列表的遍历方法主要有三种&#xff0c;使用方法和特点如下&#xff1a; lst list("hello") print("第一种遍历方式&#xff0c;使用for循环&#xff0c;循环变量item直接就是lst中的元素") for item in lst:print(item,end"\t")print("\n…

LeetCode 383.赎金信(模拟,for(char c : 容器)的使用)

给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1a; 输入&#…

第64天:服务攻防-框架安全CVE复现Apache ShiroApache Solr

目录 思维导图 案例一&#xff1a;Apache Shiro-组件框架安全 shiro反序列化 cve_2016_4437 CVE-2020-17523 CVE-2020-1957 案例二&#xff1a;Apache Solr-组件框架安全 远程命令执行 RCE&#xff08;CVE-2017-12629&#xff09; 任意文件读取 AND 命令执行&#xff08…

【java】(软考)面向对象---责任链解析

目录 责任链的意义 手写笔记 ​编辑 责任链的意义 当您把请求给出时&#xff0c;如果某对象不能实现您的操作&#xff0c;责任链会自动把您的请求传给它的下一级 从而避免请求的发送者和接受者之间的耦合关系 这里以2007年下半年试题七进行说明 题目描述 某企业的采购审批…

SpringBoot学习之Kafka下载安装和启动(三十三)

一、Mac环境 1、下载Kafka&#xff1a;Apache Kafka 2、这里我选择的版本是kafka_2.12-3.7.0&#xff0c;下载最新版的Kafka二进制文件&#xff0c;解压到你喜欢的目录&#xff08;建议目录不要带中文&#xff09;。 3、启动ZooKeeper服务&#xff0c;Kafka需要使用ZooKeeper&…

OpenHarmony 网络管理-Socket连接

介绍 本示例主要演示了Socket在网络通信方面的应用&#xff0c;展示了Socket在两端设备的连接验证、聊天通信方面的应用。 效果预览 使用说明 1.搭建服务器环境&#xff1a;修改服务器脚本中的服务端IP地址&#xff0c;与本机IP地址保持一致&#xff0c;修改完成后双击运行脚…

Zynq 7000 系列中的JTAG和DAP子系统

Zynq 7000系列SoC器件通过标准JTAG调试接口提供调试访问。在内部&#xff0c;SoC设备器件在处理系统&#xff08;PS&#xff09;内部实现了一个Arm调试访问端口&#xff08;DAP&#xff09;&#xff0c;同时在可编程逻辑&#xff08;PL&#xff09;内部实现了一个标准的JTAG测试…

minio如何配置防盗链

MinIO 是一个开源的对象存储服务器&#xff0c;用于存储大量的数据&#xff0c;同时提供了丰富的功能和 API。配置防盗链可以帮助你控制谁可以访问存储在 MinIO 上的对象。以下是在 MinIO 中配置防盗链的一般步骤&#xff1a; 编辑 config.json 文件&#xff1a; 找到 MinIO 服…

每日昨日之螺旋矩阵

螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a; 输入&#xff1a;…

文心一言 VS 讯飞星火 VS chatgpt (241)-- 算法导论17.3 7题

七、为动态整数多重集 S (允许包含重复值)设计一种数据结构&#xff0c;支持如下两个操作&#xff1a;① INSERT(S,x) 将 x 插入 S 中&#xff1b;② DELETE-LARGER-HALF(S) 将最大的 ⌈|S|/2⌉ 个元素从S中删除。解释如何实现这种数据结构&#xff0c;使得任意 m 个 INSERT 和…

spring高级篇(二)

1、Aware和InitializingBean Aware和InitializingBean都与Bean的生命周期管理相关。 Aware接口: 概念: Aware接口是Spring框架中的一个标记接口&#xff0c;它表示一个类能够感知到&#xff08;aware of&#xff09;Spring容器的存在及其特定的环境。Spring框架提供了多个Awar…

sublime运行编译C和Java

1.先安装终端 参照以下教程 如何在 Sublime 文本编辑器中使用终端&#xff1f;_sublime终端窗口怎么打开-CSDN博客 可能遇到的问题&#xff1a;有些sublime text3可能并没有显示“package control”。这个问题对于笔者来说是有些吊诡的&#xff0c;因为之前一开始安装时是能…

nginx容器化方案预研

一、概述 目前 nginx迁移升级不方便,且生产环境没有编译环境,导致生产环境nginx版本过旧、目前存在安全漏洞无法升级。运维建议容器化nginx,因此预研了此容器方案 二、镜像制作 基础镜像 cloudservice-alpine-base-v1.tar 2.1 加载基础镜像 docker load -i cloudservic…

C++恶魔轮盘赌(道具版)

家人们&#xff0c;更新了昂&#xff0c;前文&#xff1a;来自阳了个阳C的恶魔轮盘赌无道具版 作为阳了个阳C的好同学&#xff0c;我光荣地揽下了道具版的重担 不多说话&#xff0c;直接上代码 #include<bits/stdc.h> #include<Windows.h> typedef long long ll…

STM32总结

1. Keil5 下载代码和编译代码需要注意的事项 下载代码&#xff1a; 安装包版本&#xff1a;确保选择与目标硬件兼容的Keil版本。工程设置&#xff1a;在下载代码前&#xff0c;检查工程的设置&#xff0c;确认芯片型号、晶振频率等信息是否正确配置。依赖库&#xff1a;确保所…

类和对象-对象特性-成员变量和成员函数分开存储

成员变量和成员函数分开存储 #include <bits/stdc.h> using namespace std; class Person{}; void test01(){Person p;//c编译器会给每个空对象也分配一个字节空间&#xff0c;是为了区分空对象占内存的位置//每个空对象也应该有一个独一无二的内存地址 cout<<si…

每天学习一个Linux命令之basename

每天学习一个Linux命令之basename 简介 在Linux系统中&#xff0c;basename是一个用于获取一个文件名或目录名的基本名称的命令。它可以用来去除路径前缀或者获取文件名的纯粹部分。basename常用于脚本编程和文件处理&#xff0c;非常实用。 基本用法 basename命令的基本语…