「设计模式」图文代码案例详解五大创建者模式建造者、原型、抽象工厂、单例模式

核心提示文章预览:一、工厂模式 1、介绍 2、实例 、典型的工厂模式 、多个工厂方法模式 、静态工厂方法模式 3、总结 二、抽象工厂模式 1、介绍 2、实例 3、实例拓展 4、

文章预览:

一、工厂模式1、简介2、示例、典型工厂模式、多个工厂方法模式、静态工厂方法模式3、总结2、抽象工厂1、简介2、示例3、示例扩展4、总结3、构建器模式1、简介2、示例3、示例扩展4、总结4、原型模式1、简介2、示例3、示例扩展4、总结5。2.简介,例子,懒,懒,饿,用法类的内部类,双锁检查,CAS〖atomic reference〗枚举单例3。总结。

首先,工厂模式

1.介绍

这种设计模式也是Java开发中最常见的模式,也称为工厂方法模式。简单地说,它提供了一种在工厂类中创建对象的方法,允许实际的调用类确定实例化对象的类型。为了提供代码结构的可扩展性,屏蔽了每个功能类中的特定实现逻辑。让外界更容易只知道语气,同时,这是去掉很多ifelse的公式。当然也可能存在一些不足,比如要实现的类很多,如何维护,如何降低开发成本。不过这些问题可以通过后续设计模式的组合逐渐减少。

2.例子

典型工厂模式

以一家生产男鞋和女鞋的工厂为例:

类和生产者接口:

男鞋和女鞋的实现类:

实际调用类别:

输出结果:

生产男鞋和女鞋的过程已经结束,退出代码为0。

,多种工厂方法模式

与典型的工厂模式相比,Factory2将每个子类实例返回封装为一个单独的方法。

这也使得在实际调用中通过调用不同的方法来获取实例成为可能:这样做的好处是你不必关心触发实例创建的逻辑,你只需要调用创建实例的专有方法。

,静态工厂方法模式

将上述工厂方法模式中的方法设置为static,这样就可以直接调用工厂类,而无需创建实例。

3.摘要

看完之后你会觉得你只是在评判男鞋还是女鞋,让你感受到了输出语句的商业,仅此而已。但是随着业务逻辑的增加,当不同的业务类型决定了各种逻辑功能时,事情就没那么简单了。比如工厂实现的实例越来越多,实例之间的关联度大大降低,这就凸显了工厂模式的重要性,充分发挥了其避免创建者与具体产品逻辑耦合、填充列表的优势。每一个业务逻辑实现都是在它所属的类中完成的,通过改变调优可以在程序中引入新的产品类型。但是这样也会带来一些问题。如果奖品类型多,变现类会迅速膨胀。因此,需要对其他模式进行优化,这将在后续的设计模式中逐步涉及。从案例来看设计模式比从理论来看更容易,因为案例是将理论缩短到实践的最佳方式。如果你有所收获,你必须努力实践它。

二。抽象工厂

1.介绍

实际上,抽象工厂在工厂模型的基础上增加了一层“工厂的工厂”。上述工厂方法模式的一个问题是,类的创建非常依赖于工厂类。如果要扩展程序,就必须修改工厂类,这违背了封闭性原则。所以从设计上来说,是有一定问题的。如何解决它们?只需要使用抽象工厂创建多个工厂类,这样一旦需要添加新的函数,就可以直接添加新的工厂类,而不需要修改之前的代码。

2.例子

还是以男鞋女鞋厂为例。与上述不同的是,这种模式将“一个工厂生产两种鞋”的业务变成了两个工厂分别生产一种鞋。

两种产品:

两家工厂:

测试:

3.示例扩展

以构建Redis集群A和B为例:

可能的问题包括:

很多服务到了Redis需要升级成集群。集群a和集群b是兼容的,以便于后续的灾难恢复。两组集群提供的连接方法不同,需要进行调整。不能影响之前的正常运行系统。

抽象工厂由代理类创建和获取,代理类为Redis操作方法类,无需任何修改即可实现集群A和集群B的数据服务。

因为集群A和集群B在分部方法提供上是不同的,所以需要做一个适配器,这个适配器类相当于。工厂类A和工厂类B实现了这个适配器接口及其方法。通过将不同的服务抽象成一个统一的服务来创建相同的业务。

4.摘要

好处是,如果你现在想增加一个功能:生产男鞋女鞋以外的鞋子,虽然这看起来不道德,但实际业务可能只是需要实现。然后只需创建一个产品实现类,实现产品接口,创建一个工厂类实现生产者接口。还可以,不用改现成的代码。然后这个设计模式就满了:单duty,开闭原理,解耦等优点。

但是,随着业务的不断扩展,可能会造成类实现的复杂性。但也可以说不是缺点,因为可以随着其他设计公式和代理类、动态加载公式的引入而减少。

第三,建设者模式

1.介绍

构建器模型解决的主要问题是,在软件系统中,有时会创建“一个复杂的对象”,它通常由各部分的对象确定过程组成;由于需求的变化,这个复杂对象的各个部分经常面临着侧重点的变化,但是组合它们的过程是相对稳定的。我们会把搭建过程留给creator类,由creator通过制作我们的搭建包来搭建不同的制作方案。

2.例子

仍然是生产产品接口及其实现类:

建筑商发出订单,分别生产3双男鞋和2双女鞋:

测试结果:

生产男鞋,生产男鞋,生产女鞋的过程已经结束,退出代码为0。

3.示例扩展

现在,在选择装修套餐的场景中,我们使用builder,结合各种材料和材料品牌,做出施工方案。

DecorationPackageMenu类通过实现IMenu接口封装了不同的材质构造方法。对外开放的参数只需要构建器把材料和品牌扔进去,让DecorationPackageMenu处理后返回给IMenu。

4.摘要

builder模式将许多函数集成到一个类中,可以创建更复杂的东西。所以与工厂模型的区别在于,工厂模型侧重于创建单个产品,而构建器模型侧重于创建符合要求的对象和多个部件。通过使用世界中的构建者模式,我们已经可以找到一些点。也就是你什么时候会选择这样的设计模式?当一些基本材料不会发生变化,而它们的组合会频繁变化时,可以选择这样的设计模式来构建代码。这种设计模式充满了单一责任、可重复技术、独立构建者、易于扩展和易于控制细节的原则。但同时,当材料很多,组合很多的时候,班级的不断扩充也会造成维护困难的问题。但是,这种设计结构模型可以将复杂的内容抽象到数据库中,并根据需要进行配置。这样可以减少代码中数量的重复。

四。原型模式

1.介绍

这种模式的思想是以一个对象为原型,复制克隆,产生一个与原对象相似的新对象。这个总结将通过复制对象来解释。

2.例子

在Java中,复制对象是通过克隆实现的。首先,创建一个原型类:

公共类Prototype实现可克隆的{公共对象克隆抛出CloneNotSupportedException { Prototype proto = super . clone;返回proto}}

很简单。原型类只需要实现可克隆的接口并覆盖克隆方法。这里,clone方法可以更改为任何名称,因为cloneable接口是空接口。可以任意定义实现类的方法名,比如Clonea或者cloneB,因为这里的重点是super.clone,它调用Object的clone方法,本身其实就是浅拷贝。首先,了解对象的深、浅复制的概念:

浅复制:复制一个对象后,所有基本数据类型的变量都会被重新创建,引用类型指向原对象。

深层复制:复制对象后,基本数据类型和引用类型都被重新创建。简单来说,深层拷贝是完全拷贝,浅层拷贝是不完全拷贝。要实现深度复制,需要以流的形式读取当前对象的二进制输入,然后写出二进制数据对应的对象。

这里,写一个深、浅抄的例子:

公共类原型实现可克隆的、可序列化的{ private static final long serial version uid = 1L;私有字符串String;私有SerializableObject obj公共对象克隆抛出clonenotsupportexception { prototype proto = super . clone;返回proto}Public Object Deep Clone抛出IO异常,ClassNotFoundException {ByteArray输出流Bos = New ByteArray输出流;object output stream OOS = new object output stream;oos.writeObjectbytearrayiputstream bis = newbytearrayiputstream);ObjectInputStream ois =新的ObjectInputStream;返回ois.readObject}公共字符串getString { return string} public void setString { this . string = string;} public serializable object get obj { return obj;} public void set obj { this . obj = obj;} }类SerializableObject实现Serializable { private static final long serialVersionUID = 1L;}

3.示例扩展

模拟出题方式,这里模拟两个试题的类;选择问题、回答问题.如果是实际业务场景开发,题型会比较多,可以回忆一下自己的考卷。

题库克隆试卷对象处理类

QuestionBankController初始化试卷数据类

这个类的内容比较简单,主要是为试卷内容提供模式初始化操作。以及对外生成试卷的方法,在生成的过程中,采用了克隆的方法;QuestionBank.clone,最后返回试卷信息。

4.摘要

上面的实际场景模拟了开发中原型模式的重构,但是原型模式出现的频率真的不是很高。如果需要实现一些特殊的场景,也可以按照这个设计模式进行优化。此外,原型设计模式的优势还包括:通过克隆很容易创建复杂的对象,还可以避免重复的初始化操作,并且不需要与类中的其他类进行耦合。但是,也有一些缺点。如果对象包含循环引用的克隆,并且类的深度使得对象克隆,这种模式会变得极其麻烦。

动词 (verb的缩写)单一模式

1.介绍

Singleton模式可以说是整个设计中最简单的模式之一,这种模式即使不看设计模式的相关信息,也经常在编码开发中。因为在编程开发中,我们经常会遇到这样的场景,那就是我们需要保证每个类只有一个实例,即使多个线程同时访问,我们也需要给这个实例提供一个全局的访问点。以及我们平时的发展,可以总结几点经验。singleton模式主要解决频繁创建和消耗全局类的问题,提高整个代码的性能。

技术场景:

spring中的数据库连接池不会重复创建singleton模式bean的和,这样一些需要全局设置的属性就保存在我们平时的代码中了。

2.例子

懒,懒

“只有当你需要的时候,我才是新的,而且只有一次”

公共类Singleton_01 {私有静态Singleton_01实例;private singleton _ 01 { } public static singleton _ 01 GetInstance { if {//返回实例只能有一个实例;} esle { instance = new Singleton _ 01;返回实例;} }}

前一种类型的singleton确实充满了懒加载,但是如果多个访问者同时得到对象实例,你可以想象一下堆在抢厕所,会造成多个相同的实例并存,永远达不到singleton的要求。

懒,懒

公共类Singleton_02 {私有静态Singleton_02实例;private Singleton _ 02 { } Public Static Synchronized Singleton _ 01 GetInstance {//如果{// return instance,则只能有一个同步锁实例;} esle { instance = new Singleton _ 01;返回实例;} }}

虽然这种模式是线程安全的,但是在方法中添加了锁之后,所有的访问都需要被锁定,导致了资源的浪费。如果不是特例,不建议用这个公式来实现singleton模式。

饥饿的中国式

“不管你要不要,我先做一个新的,就一次。”

公共类Singleton_03 {私有静态Singleton _ 03 instance = new Singleton _ 03;private Singleton _ 03 { } public static Singleton _ 03 getInstance { return instance;}}

解释:由于实例是一个静态实例,它与类一起加载。调用静态方法getInstance时,总是返回从头加载到内存中的实例,从而达到singleton的效果。但是,这种类型不是懒加载,也就是说,不管你的程序中有没有发现这样的类,它都会在程序启动之初创建。那么这种类型导致的问题就像下载了一个游戏软件。也许你的游戏地图还没有打开,但是程序已经实例化了所有这些地图。当你在你的机器上有最明显的经验时开始游戏。内存满了,机器卡了,要换了。

,请使用类的内部类。

这种单例模式经常被推荐。使类的静态内部类实现singleton模式,既保证了线程安全又保证了延迟加载,即在使用时,内部类SingletonHolder将只通过调用getInstance方法来加载,从而实现延迟加载,同时也不会因为锁定而消耗性能。这主要是因为JVM虚拟机可以保证多线程并发访问的正确性,即在多线程环境下可以正确加载一个类的构造方法。

公共类Singleton_04 {私有Singleton_04 { }私有静态类SingletonHolder {私有静态Singleton _ 04 instance = new Singleton _ 04;}公共静态Singleton _ 04 getInstance { return Singleton holder . instance;}}

,双重锁定检查

公共类Singleton_05 {私有静态Singleton_05实例;private Singleton _ 05 { } public static Singleton _ 05 getInstance { if { return instance;} synchronized {//保证线程安全if { instance = new Singleton _ 05} }返回实例;}}

双锁法是律级锁的优化,实际上是懒线程安全版的性能优化。因为lazy方法是用方法lock添加的,所以每次调用getInstance时,对象都必须被锁定。事实上,只有在第一次创建对象时才需要锁,因此可以将其更改为上面的形式。减少了获取某些实例的耗时。同时,这种类型充满了懒装。

、CAS「原子参照」

public class Singleton _ 06 { private static final atomic reference ar = new atomic reference;私有静态Singleton_06实例;private Singleton _ 06 { } public static final Singleton _ 06 getInstance { for { Singleton _ 06 instance = ar . get;如果返回实例;ar . compareandset);返回ar . get;} }公共静态void main { system . out . println);//org . it stack . demo . design . singleton _ 06 @ 2b 193 f2d system . out . println);//org . it stack . demo . design . singleton _ 06 @ 2b 193 f2d } }

Java并发库为并发访问的数据安全提供了许多独创的类:AtomicInteger、AtomicBoolean、AtomicLong、AtomicReference。AtomicReference可以封装引用一个V实例,上面的并发访问的singleton做了这样一个特性。CAS的优势在于不需要使用传统的锁方法来保证线程安全,而是依靠CAS的繁忙算法和底层硬件的实现来保证线程安全。与其他锁实现相比,因为没有线程切换和阻塞,所以没有额外的开销,并且可以保持更好的并发性。当然CAS也有一个缺点,就是忙着等。如果得不到,就会无限循环。

枚举单例

公共枚举Singleton _ 07 { INSTANCEpublic void test { system . out . println;}}

@ test public void test { Singleton _ 07。INSTANCE.test}

Effective Java的作者推荐使用枚举公式来解决singleton模式,这可能是最不常见的。这个公式解决了最重要的问题:线程安全、序列化和单实例。补偿有效地提供了一种序列化机制,这种机制绝对可以防止这种情况被实例化,即使在复杂的序列化或反射攻击的情况下。虽然这种方法还没有得到广泛的应用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。但是,我们也要知道,在继承的情况下,这个公式是不可或缺的。

3.摘要

虽然只是常见的singleton模式,但是你真的可以在各种实现中看到java的基本功,包括懒人,饿人,线程是否安全,静态类,内部类,加锁,序列化等等。在平时的开发中,如果能保证这个类是全局的,不需要做懒加载,直接创建,外部调整就可以了。但是,如果类很多,而且有一部分需要在用户触发一定条件后才显示,那么一定是懒加载。可以根据需要选择线程安全性。

,https://blog . csdn . net/weixin _ 45296116/article/details/121055884

 
友情链接
鄂ICP备19019357号-22