Java设计模式之到单例模式和原型模式

记录设计模式相关知识,包括设计模式定义,设计原则(单一职责,开闭原则,依赖倒置,里式替换,接口隔离,迪米特原则,组合聚合复用原则),单例模式,原型模式并提供代码示例

文章目录

  • 一、设计模式介绍
  • 二、设计原则
  • 三、设计模式
    • 单例模式
    • 原型模式


正文内容:

一、设计模式介绍

设计模式是一种设计规范,对于一类问题合理解决的思路与方式,更高效解决一类问题,对于编码来讲就是可以提高程序代码的可读性,可扩展性,复用性

  1. 可以提高程序员的思维能力,编程能力和设计能力
  2. 使程序更加标准化,使软件开发效率大大提高
  3. 使设计的代码可重用性高,可读性强,可靠性高,灵活性好,可维护性强
  4. 更好的理解源码架构

通过设计模式帮助程序员构建更完善的系统编码;编码过程中找到需求会发生变化的地方与不会发生变化的地方,将两者分离开;面向接口编程,而不是面向实现编程;实现高内聚低耦合

二、设计原则

  1. 单一职责
    在设计的时候尽量让类,或者方法只处理单一事件(高内聚低耦合)
  2. 开闭原则
    对扩展开放,对修改关闭;对于类或者方法进行功能增强是支持的;对于类或者方法的修改关闭,不在原有类或者方法上面进行修改;为满足开闭原则,一般使用抽象化设计
  3. 里氏替换(LSP)
    一个超类的对象应该能够被一个子类的对象替换,而不影响程序的正确性
    换句话说,如果一个程序使用了基类,那么它应该能够使用任何派生类的对象,只要该派生类满足基类的行为期望。LSP确保子类可以替换其基类

代码示例如下:

interface Shape {int area();
}class Rectangle implements Shape {private int width;private int height;public Rectangle(int width, int height) {this.width = width;this.height = height;}@Overridepublic int area() {return width * height;}
}class Square extends Rectangle {public Square(int side) {super(side, side);}
}class AreaCalculator {public static int computeArea(Shape[] shapes) {int totalArea = 0;for (Shape shape : shapes) {totalArea += shape.area();}return totalArea;}
}public class Main {public static void main(String[] args) {Shape[] shapes = new Shape[] {new Rectangle(2, 3),new Square(2),new Rectangle(3, 4),new Square(3)};System.out.println(AreaCalculator.computeArea(shapes));}
}

在这个例子中,我们有一个Shape接口,其中有一个抽象方法area,它将被子类重写。Rectangle类实现了area方法,Square类继承了Rectangle类并重写了Square构造函数,以保持宽度和高度相等,创建了一个正方形。

AreaCalculator类的computeArea方法接受一个Shape对象数组,并计算所有形状的总面积。此方法可以与任何类型的Shape对象(包括Rectangle和Square)一起使用,而不必知道特定类型。这是因为Square类满足Shape类的预期行为,可以代替Rectangle,而不影响程序的正确性。

LSP是一个重要的原则,因为它通过继承实现代码复用,从而帮助创建灵活和易于维护的代码库。它还有助于防止错误,并确保即使在代码发生更改时程序仍然可以正常工作。

  1. 依赖倒置
    上层模块不应该依赖底层模块,都应该依赖抽象;抽象不依赖于细节,细节应该依赖于抽象
  2. 接口隔离
    使用多个接口,而不是使用单一的总接口,不强迫新功能实现不需要的功能
  3. 迪米特原则
    一个对象对于其他对象有最少了解
    比如说存在学院类,学校类,管理类,管理类存在方法,需要将学院信息,学校信息进行输出;此时根据迪米特原则,分别将学员信息,学校信息访问方法设计在学院类与学校类,在管理类中调取这两个访问方法即可
  4. 组合/聚合复用原则
    模块A需要复用模块B时,根据模块之间的关联程度,尽量使用组合/聚合关系进行复用,减小模块之间的耦合程度

三、设计模式

单例模式

单例模式:类是一类事物共同属性,行为的抽象;具体到类中事物共同属性将会抽象成为类中的成员属性,行为将会抽象成为类中的方法,类中还包括构造器,用于创建出一个具体的事物,也就是Java中的对象,通过构造器,可以创建多个对象,但是有的时候程序不需要多个对象,对于这个类只需要创建一个对象时,就需要使用单例模式

实现思路:将构造器私有化,外部无法创建对象;但是此时需要该类对象,所以需要提供外部方法供其他类访问该对象;通过将类引用使用static修饰保证对象在整个程序运行期间的存在;程序还需要保证对象的唯一性,最简单(不安全,不建议)的实现可以这样子:

public class Singleton{private static Singleton singleton = new Singleton();private Singlrton(){}public static Singleton getInstance(){return singleton;}
}

上面代码在对象引用位置就创建对象;就和饿汉看见食物之后很急切的开始吃食一样,所以上述代码有很形象的名称:饿汉式单例模式,与之对应的还包括懒汉模式;懒汉模式与饿汉模式最大的差别是两者创建对象的时期不一样,懒汉式只有在对象第一次使用的时候创建,将对象的创建时期推后,需要考虑线程安全问题,线程安全的懒汉式单例模式代码如下所示:

public class Singleton {private static volatile Singleton singleton;private Singleton() {}public static  Singleton getInstance() {if (singleton==null){synchronized (Singleton.class){if (singleton == null) {singleton = new Singleton();}}}return singleton;}
}

在双重检锁单例模式中判断instance是否为null的原因是,如果instance已经被实例化了,那么就没有必要进入加锁的代码块,直接返回已经实例化的instance即可。而第二次判断instance是否为null的原因是,在多线程环境下,可能存在多个线程同时通过了第一次判断,进入了加锁的代码块,但只有一个线程会获得锁,实例化instance对象并将其赋值给instance变量。如果没有第二次判断,那么其他线程在获得锁后也会再次实例化一个instance对象,这就破坏了单例模式的原则,因为这样就不再只有一个instance对象了。

在第二次判断中,为了确保在多线程环境下,instance变量的可见性和一致性,通常会使用volatile关键字进行修饰。volatile关键字可以保证所有线程对instance变量的访问都是直接读写主存,而不是读写线程私有的副本,从而避免了可能的可见性和一致性问题。

原型模式

原型模式:是一种创建型设计模式,它允许通过克隆现有对象来创建新对象,而不是通过实例化新的对象并赋值来创建新对象。原型模式主要涉及到两个角色,即原型(Prototype)和具体原型(Concrete Prototype)。其中,原型是一个抽象类或接口,定义了一个 clone() 方法,用于复制自身;具体原型则是实现了原型接口的具体类,它的 clone() 方法可以创建一个当前对象的副本。通过复制现有的对象,原型模式可以避免在创建对象时昂贵的构造过程,从而提高了创建对象的效率。

在使用原型模式时,通常需要在程序中创建一个原型对象,并将其存储在一个原型管理器(Prototype Manager)中。当需要创 建新对象时,可以从原型管理器中获取一个原型对象,然后通过克隆方法创建新对象。

以下是原型模式的基本结构:

  • 抽象原型(Prototype):定义一个克隆自身的接口方法。

  • 具体原型(Concrete Prototype):实现抽象原型的克隆方法,用于复制自身。

  • 原型管理器(Prototype Manager):用于存储和管理原型对象。

    原型模式的优点包括:

  • 可以避免创建对象时昂贵的构造过程,从而提高创建对象的效率。

  • 可以动态添加和删除原型对象。

  • 可以实现深拷贝和浅拷贝,以便灵活地复制对象。

    原型模式的缺点包括:

  • 需要为每个类配备一个克隆方法,这增加了代码量。

  • 克隆方法对于含有循环引用或引用其他不可序列化的对象的复制会比较困难。

  • 使用原型模式时需要注意深拷贝和浅拷贝的问题。

代码实现如下所示:

public abstract class Shape implements Cloneable {private String id;protected String type;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getType() {return type;}public abstract void draw();@Overridepublic Object clone() {Object clone = null;try {clone = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}
}public class Rectangle extends Shape {public Rectangle() {type = "Rectangle";}@Overridepublic void draw() {System.out.println("Inside Rectangle::draw() method.");}
}public class Square extends Shape {public Square() {type = "Square";}@Overridepublic void draw() {System.out.println("Inside Square::draw() method.");}
}public class Circle extends Shape {public Circle() {type = "Circle";}@Overridepublic void draw() {System.out.println("Inside Circle::draw() method.");}
}public class ShapeCache {private static Map<String, Shape> shapeMap = new HashMap<>();public static Shape getShape(String shapeId) {Shape cachedShape = shapeMap.get(shapeId);return (Shape) cachedShape.clone();}public static void loadCache() {Circle circle = new Circle();circle.setId("1");shapeMap.put(circle.getId(), circle);Square square = new Square();square.setId("2");shapeMap.put(square.getId(), square);Rectangle rectangle = new Rectangle();rectangle.setId("3");shapeMap.put(rectangle.getId(), rectangle);}
}public class PrototypePatternDemo {public static void main(String[] args) {ShapeCache.loadCache();Shape clonedShape = (Shape) ShapeCache.getShape("1");System.out.println("Shape : " + clonedShape.getType());Shape clonedShape2 = (Shape) ShapeCache.getShape("2");System.out.println("Shape : " + clonedShape2.getType());Shape clonedShape3 = (Shape) ShapeCache.getShape("3");System.out.println("Shape : " + clonedShape3.getType());}
}

这里定义了一个抽象类Shape,包含一个draw抽象方法和一个clone方法,并有三个子类分别继承自Shape,实现了draw方法。ShapeCache类用于缓存Shape对象,其中使用getShape方法获取缓存的对象并使用clone方法进行复制。在PrototypePatternDemo类中,通过缓存获取Shape对象并复制,从而达到原型模式的效果。

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

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

相关文章

spring复习:(22)实现了BeanNameAware等Aware接口的bean,相应的回调方法是在哪里被调用的?

AbstractAutowireCapableBeanFactory的doCreateBean用来创建bean, 其中调用了initializeBean方法对bean进行初始化 initializeBean包含如下代码&#xff1a; 而invokeAwareMethods代码如下&#xff1a; 可见其分别判断是否实现了BeanNameAware接口、BeanClassLoaderAware接口…

基于ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升技术

空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与注记 2.4 研究区…

在Matlab、VST和C中深度探讨使用FxLMS、FuLMS、NLMS等各种算法进行主动噪声消除与音频信号处理的详细操作

第一部分&#xff1a;引言及算法基础 在多媒体通信、音频处理、音乐创作和其他相关领域&#xff0c;噪声消除和音频信号处理成为了重要的问题。在这篇博客中&#xff0c;我们将深入探讨在Matlab、VST和C编程语言环境中&#xff0c;如何使用FxLMS、FuLMS、NLMS等各种算法进行主…

Maven下载和配置教程:Windows、Mac和Linux系统安装指南

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Nginx配置白名单访问

一、背景 在项目运行的时候&#xff0c;需要设置特定的访问权限&#xff0c;以拒绝其他可能存在的恶意访问。 二、配置 2.1、关键字 允许访问关键字&#xff1a;allow 屏蔽访问关键字&#xff1a;deny 2.2、作用域 作用域如下&#xff1a; http&#xff1a;所有网站屏蔽I…

如何搭建自己的图床(GitHub版)

文章目录 1.图床的概念2.用GitHub创建图床服务器2.1.新建仓库2.2.生成Token令牌2.3.创建img分支和该分支下的img文件夹(可选) 3.使用PicGo软件上传图片3.1 下载PicGo软件3.2配置PicGo3.3用PicGo实现上传 4. Typora实现自动上传5.免费图片网站 前言&#xff1a; 如果没有自己的服…

mysql中什么是表?列?行?什么是主键和外键?什么是索引?为什么要使用索引?

mysql中什么是表&#xff1f;列&#xff1f;行&#xff1f; 在关系数据库中&#xff0c;表&#xff08;Table&#xff09;是数据的主要组织单元。它是由一组命名的列和行组成&#xff0c;用于存储和组织数据。 列&#xff08;Column&#xff09;是表中的一个字段&#xff0c;…

【C语言例题】接收一个整型值(无符号),按照顺序打印它的每一位

一、题目要求 接受一个整型值&#xff08;无符号&#xff09;&#xff0c;按照顺序打印它的每一位。 例如&#xff1a; 输入&#xff1a;1234&#xff0c;输出 1 2 3 4 二、解法剖析 首先要明确我们的目标&#xff0c;既然是要按顺序打印每一位&#xff0c;那么就离不开 /10 和…

ARM Coresight 系列文章 7 - ARM Coresight 通过 AHB-AP 访问 cpu 内部 coresight 组件

文章目录 如下图所示&#xff0c;如果A78想去访问M33的内部 coresight 组件 ETM&#xff0c;需要要怎么做&#xff1f; 答案也正是在图中&#xff0c;首先A78 通过AXI 互联&#xff0c;接入到 APBIC 的 slave port&#xff0c;再通过APBIC 的 master 送出&#xff0c;而APBIC中…

网安学习经历小记

明明自觉学会了不少知识&#xff0c;可真正开始做题时&#xff0c;却还是出现了“一支笔&#xff0c;一双手&#xff0c;一道力扣&#xff08;Leetcode&#xff09;做一宿”的窘境&#xff1f;你是否也有过这样的经历&#xff0c;题型不算很难&#xff0c;看题解也能弄明白&…

MySql高级篇-006 MySQL架构篇-02MySQL的数据目录:数据库下的主要目录结构、文件系统如何存储数据

第02章_MySQL的数据目录 1.MySQL8的主要目录结构 # 查询名称叫做mysql的文件目录都有哪些[rootatguigu07 ~]# find / -name mysql安装好MySQL 8之后&#xff0c;我们查看如下的目录结构&#xff1a; 1.1 数据库文件的存放路径 MySQL数据库文件的存放路径&#xff1a;/var/…

Foxit PDF ActiveX 5.9.8 Crack

Foxit PDF SDK ActiveX 即时添加PDF显示功能至Windows应用程序&#xff0c;快速投放市场&#xff0c;可视化编程组件功能强大且易于使用的PDF软件开发工具包 对于刚接触PDF或不愿投入过多精力学习PDF技术的产品管理者及开发者来说&#xff0c;Foxit PDF SDK ActiveX无疑是理想…

第二十章:CANet:具有迭代细化和专注少样本学习的无类别分割网络

0.摘要 最近在语义分割方面的进展是由深度卷积神经网络和大规模标注图像数据集推动的。然而&#xff0c;像素级别的数据标注是繁琐和昂贵的。此外&#xff0c;训练好的模型只能在一组预定义的类别中进行预测。在本文中&#xff0c;我们提出了CANet&#xff0c;一种无类别偏见的…

现代化 Android 开发:Jetpack Compose 最佳实践

作者&#xff1a;古哥E下 如果一直关注 Compose 的发展的话&#xff0c;可以明显感受到 2022 年和 2023 年的 Compose 使用讨论的声音已经完全不一样了, 2022 年还多是观望&#xff0c;2023 年就有很多团队开始采纳 Compose 来进行开发了。不过也有很多同学接触了下 Compose&am…

大文件下载优化方案(nginx+Springboot+vue)---非常完美

1、背景&#xff1a; 系统中有个文件下载的功能&#xff0c;下载的文件从1k-几十G不等&#xff0c;小文件下载没有问题&#xff0c;只要上G了&#xff0c;下载大概率失败。基于以上现状&#xff0c;对技术方案记性优化。 2、历史方案&#xff1a; 2.1 服务器读取文件流传输前…

基于深度学习的高精度鸟类目标检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度鸟类目标&#xff08;鹦鹉&#xff08;Crested Myna&#xff09;、麻雀&#xff08;Eurasian Tree Sparrow&#xff09;、黑头文鸟&#xff08;Chestnut Munia&#xff09;、白领翡翠&#xff08;Collared Kingfisher&#xff09;、太阳鸟…

Redis深入——管道、发布订阅、主从复制、哨兵监控和集群

前言 在前面的学习中&#xff0c;我们已经了解了Redis的基本语法以及Redis持久化和事务的概念。而在这篇文章中我们继续来梳理管道、发布订阅、主从复制、哨兵监控和集群的知识&#xff0c;理解Redis主从复制到集群分片的演进过程&#xff0c;希望对正在学习的小伙伴有一定的帮…

C语言—数据类型

文章目录 1 基本数据类型2 数组&#xff0c;字符数组和字符串2.1 数组2.2 字符数组与字符串 3 枚举类型4 结构体和共用体4.1 结构体4.2 共用体 5. 拓展5.1 结构体内存分配5.1.1 以结构体中占字节数最大的数据类型的字节数为单位开辟内存5.1.2 字节对齐5.1.3 结构体中嵌套结构体…

区块链生态发展

文章目录 前言以太坊的到来什么是图灵完备&#xff1f;什么是智能合约&#xff1f; 以太坊的应用去中心化应用 DApp代币发行 公有链&联盟链区块链应用总结 前言 前面的区块链文章有介绍区块链的诞生以及底层运行原理&#xff0c; 本文主要介绍一下区块链应用的发展&#x…

ensp静态路由

要求&#xff1a; 1.全网可达 2.拓朴中所需地址全部基于192.168.0.0/24 3.静态路由&#xff08;不许使用其他动态&#xff09; 4.R2环回需要汇总 拓朴图&#xff1a; 将192.168.0.0/24划分为5个子网&#xff0c; 得&#xff1a; 192.168.0.0/27 192.168.0.32/27 192.168.0.64/…