设计模式学习笔记(一)

设计模式学习笔记(一)

一般说设计模式都是指面向对象的设计模式,因为面向对象语言可以借助封装、继承、多态等特性更好的达到复用性、可拓展性、可维护性。

面向对象一般指以类、对象为组织代码的基本单元,并将封装、继承、多态、抽象四个特性(抽象有的定义里并不认为是四大特性)作为代码设计与实现的基石。

  • 封装:通过访问权限控制,只对外暴露必要的操作,保护数据。

  • 继承:代码复用,结构美感。不过 Java 语言不支持多重继承,原因是如果 BC 都继承了 A 并重写了某个方法,D 同时继承 BC 会产生歧义。

  • 多态:提高代码的复用性,主要通过两种方式实现

    • 继承:父类引用指向子类对象
    • 实现:接口引用指向具体实现类
  • 抽象:有时并不计入四大特性,用来保护实现,例如接口就是对实现的一种抽象,无需关注实现

有些设计看似是面向对象

  • 滥用 getter、setter 方法。lombok 的注解确实很方便,但这样其实违背了面向对象的封装特性,例如 createTime 等字段其实是不需要 setter 方法的,需要在创建对象的时候就确定。
  • 滥用全局变量、全局方法(Constants、Utils)。这样会导致修改后所有引用的地方都重新编译,而且有的时候只需要其中的某几个变量(或方法)却导入了整个类。
    • 功能拆分,不要定义一个大而全的类。例如 Constants 拆分为 DateConstants、RedisConstants、MysqlConstants
  • 定义数据与方法分离的类。传统的 MVC 开发中,数据在相应的 BO、VO、PO 中,而操作却封装在对应的 Controller、Service 中,这就是典型的面向过程,也就是“贫血模型”的开发方法。不过这样的开发方式依然很流行,因为大部分的需求并不复杂,甚至只是从数据库中找到查哪些字段,组织对应的 VO,先写 service 反推 controller。

如何理解接口与抽象类

随着 jdk 版本的更新,接口也可以有默认实现,也可以定义变量作为常量使用。抽象类依然不允许被实例化,继承抽象类必须重写抽象类的所有方法。

先说结论:抽象类的作用更多是为了代码复用,而接口的作用则更偏向与“协议”,具备什么样的功能。

public class BaseEntity implements Serializable {private static final long serialVersionUID = 8417380540303280008L;@ApiModelProperty(value = "所属用户标识")@Column(name = "USER_ID")private String userId;@ApiModelProperty(value = "记录是否有效,默认为1表示有效")@Column(name = "ACTIVE")private String active;@ApiModelProperty(value = "创建时间,默认为当前时间")@Column(name = "CREATED_AT", updatable = false)@DateTimeFormat(pattern = Constants.PATTERN_DATE_HOUR_MINUTE_SECOND)@JsonFormat(pattern = Constants.PATTERN_DATE_HOUR_MINUTE_SECOND, timezone = Constants.TIMEZONE)private Date createdAt;@ApiModelProperty(value = "更新时间")@Column(name = "UPDATED_AT")@DateTimeFormat(pattern = Constants.PATTERN_DATE_HOUR_MINUTE_SECOND)@JsonFormat(pattern = Constants.PATTERN_DATE_HOUR_MINUTE_SECOND, timezone = Constants.TIMEZONE)private Date updatedAt;}

例如我们有一个上面的类,对于一个正常的删除来讲,一方面我们要查询这个数据是否存在(例如有些系统删除不存在的空数据会返回错误),另一方面判断当前登录用户是否具有删除权限(即资源的 USER_ID 是否为当前登录人或是否是当前登录人的下属),最后还需要记录日志。

public void delete(String uuid) {Entity entity = getEntityFromDB(uuid);if (entity == null) {throw ......}if (entity instanceof BaseEntity) {BaseEntity e = (BaseEntity)entity;if (!e.getActive.equals("1")) {} else {e.setActive("0");saveEntityToDB(entity);}}
}protected abstract T saveToDataBase(T entity);protected abstract Entity getEntityFromDB(String uuid);

借助抽象类与多态,可以提高代码的复用性,减少重复代码。

如何理解基于接口而非实现编程

假如目前有一个上传图片到公有云的需求

public class uploadPictureAliyunImpl {// 获取合法 tokenpublic String getToken() {};// 如果目录不存在就创建目录public boolean createDictoryIfNotExists() {};// 上传图片public boolean uploadPictureToAliyun() {};}public class Main() {public static void Main () {uploadPictureAliyunImpl impl = new uploadPictureAliyunImpl();String token = impl.getToken();........}
}

如果这样实现,后期替换为其他云厂商,例如自有的私有云,就需要替换很多代码,实际上这种情况只需要定义一个上传图片的接口,由不同的存储来实现就行。

基于接口编程,即进行更好的抽象设计,不暴露过多实现。

为什么说多用组合少用继承

以鸟(bird)为例,可以分为是否会飞、是否会下蛋…

image-20250916170508725

当继承层次越来越深,关系会越来越复杂,会严重影响代码的稳定性与可维护性。但是当继承层次很浅且业务稳定时,依然可以利用继承和多态特性来实现特定功能。

继承实际上可以替换为组合来实现,例如定义两个接口:

public interface Flyable {void fly();
}public interface Eggable {void egg();
}

每一种鸟类根据自己的情况来实现对应接口即可,但是这会引入新的问题,例如有 n 个鸟类实现的 fly 接口都是一样的,那代码重复会十分严重,解决方式就是“委托”:

public class DefaultFlyableImpl implements Flyable {void fly() {......}
}public class AAABird implements Flyable {// 其实一般是使用注解注入private DefaultFlyableImpl defaultFlyImpl = new DefaultFlyableImpl();void fly() {defaultFlyImpl.fly();}}

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

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

相关文章

【CSS】一个自适应大小的父元素,如何让子元素的宽高比一直是2:1

父元素是自适应大小的容器(比如 width:100%),我们希望子元素 始终保持 2:1 宽高比(比如宽 200px → 高 100px,宽 300px → 高 150px)。 有几种常见解法:✅ 方法一:CSS aspect-ratio&…

如何搭建redis集群(docker方式非哨兵)

1、redis的配置文件这里要注意,主从的ip不需要我们去设置,只需要设置主从的密码就可以,然后就是protect-mode,我设置的是no,一定注意不能设置主从。客户端要访问,一定要加# 每个节点的 redis.conf 中 clust…

如何学习VBA_3.3.9:利用“搭积木”思想,快速有效地完成你的代码

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的劳动效率,而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册,现在已经全部完成,希望大家利用、学习。如果您…

JSP程序设计之输入/输出对象 — response对象

response对象1.概述2.实例:response对象方法运用(1)实例一:页面自动刷新(2)实例二:实现页面重定向,具体的代码(3)综合实例:实现登录并记录用户名1…

Redis 事件驱动框架(ae.c_ae.h)深度解析

Redis 事件驱动框架(ae.c/ae.h)深度解析 之前咱们用 “超市收银员” 的例子,简单看懂了 ae 模块是 Redis 的 “多任务神器”。现在咱们再往深走一层,不用复杂代码,只拆它的 “核心运作逻辑”—— 搞懂它怎么做到 “一个…

[能源化工] 面向锂电池RUL预测的开源项目全景速览

锂离子电池是新能源汽车、储能系统及便携式电子设备的核心能源部件,其剩余使用寿命(Remaining Useful Life,RUL)的准确预测直接关系到设备运行安全、维护成本优化和能源效率提升。RUL预测算法能够提前量化电池剩余可用时间&#x…

PEFT QLora Deepspeed Zero Stage 3 Offload Trainning

使用 accelerate deepspeed zero stage 3 offload 进行 sft trainning 的自动设备映射: GPU 训练计算 CPU 存储 run_peft_qlora_deepspeed_stage3.sh #!/bin/bashexport MAX_JOBS4 export OMP_NUM_THREADS4 export disable_exllamaTrue export CUDA_VISIBLE_DEVICES0,1 expor…

JAVA上门家政维修服务系统源码微信小程序+微信公众号+APP+H5

一、功能介绍用户端:精准分类、支持家政、维修、万能服务、一口价、报价、线上、各类家政服务、优惠专区、师傅入驻、商家入驻、我的需求、补费明细、我的投诉;师傅端:接单池、消息通知、接单管理、今日订单、师傅入驻、我的钱包、实名认证&a…

GCKontrol对嵌入式设备FPGA设计流程的高效优化

1 前言FPGA(Field-Programmable Gate Array,现场可编程逻辑门阵列)是一种可编程的半导体器件,因其硬件可重构性、硬件并行计算能力、低延迟和实时性的优势,广泛应用于数字电路设计、原型验证和系统加速等领域。但开发…

DBAPI免费版对比apiSQL免费版

DBAPI简介 零代码开发api服务,只需编写sql,就可以生成http api服务。支持api动态创建,兼容多种数据库。 适用于BI报表、数据可视化大屏的后端接口快速开发。 旨在为企业数据服务的发布提供完整解决方案 一、DBAPI免费版本支持1个数据源连接支…

CTFHub SSRF通关笔记8:数字IP Bypass 原理详解与渗透实战

目录 一、SSRF 二、数字IP原理 1、IP多进制 (1)十进制整数格式 (Dword / 长整数格式) (2)八进制格式 (Octal IP) (3)十六进制格式 (Hex IP) 2、SSRF绕过 三、渗透实战 1、打开靶场 2、尝试127.0.…

C++中双引号和单引号的区别(全面分析)

我在刷算法题的时候经常遇到,用了 出现警告或者使用" "直接报错,尤其是在字符串部分(py玩家后遗症/(ㄒoㄒ)/~~)在详细了解后总结一下加强记忆。 总的来说在 C 中,双引号 "" 和单引号 是完全不同…

Ubuntu20.04仿真 |iris四旋翼添加云台相机详述

申明: 1、本人使用的是Ubuntu20.04ros1gazeboxtdronepx4的仿真组合 2、为了使传感器模型和飞机模型解耦合,实现不同平台对传感器可直接调用,本系列博文涉及的所有传感器均不直接添加在相应平台的sdf当中,而是通过编写xxx_joint.…

《人工智能AI之机器学习基石》系列 第 16 篇:关联规则与数据挖掘——“啤酒与尿布”传奇背后的增长秘密

《人工智能AI之机器学习基石》⑯ 专栏核心理念: 用通俗语言讲清楚机器学习的核心原理,强调“洞察+ 技术理解 + 应用连接”,构建一个完整的、富有启发性的知识体系。 引言:藏在购物车里的“读心术” 朋友们,欢迎回到我们的AI基石之旅。 在过去的两次探索中,我们深入…

Spring Boot 的自动配置原理

Spring Boot 的自动配置是其 "约定大于配置" 理念的核心实现,它能自动配置 Spring 应用所需的各种组件,大幅减少手动配置。下面从核心注解、加载流程、条件过滤等方面详细讲解其原理,并结合关键源码说明。一、自动配置的入口&#…

谷歌云平台(Google Cloud Platform, GCP)介绍(全球领先的云计算服务平台,为企业和开发者提供包括计算、存储、数据分析、人工智能、机器学习、网络和安全等在内的全面云服务)

文章目录**1. GCP的核心优势****1.1 全球领先的基础设施****1.2 强大的数据分析和人工智能能力****1.3 卓越的安全性和合规性****1.4 灵活的定价模式****2. GCP的主要服务****2.1 计算服务****2.2 存储和数据库****2.3 网络服务****2.4 人工智能与大数据****2.5 安全与管理工具…

RISC-V异常机制和异常定位

不少人在调试RISC-V core时,面对异常的出现不知所措,不知道如何定位代码问题。这里将从RISC-V异常机制以及几个异常实例学习下。 1 异常机制 1.1 什么是异常 异常是软件程序员不得不要深入了解的,首先在学习异常机制前,对异常要…

c++中导出函数调用约定为__stdcall类型函数并指定导出函数名称

开发环境在Visual studio 2022版本下,为防止编译器重命名函数名称(会加上8等等乱七八糟的东西),我们对函数名称进行指定:一、新建.def文件,名称须与dll名称相同,并放在与cpp文件相同文件夹下&am…

Vision Transformer (ViT) :Transformer在computer vision领域的应用(二)

METHOD,论文主要部分 In model design we follow the original Transformer (Vaswani et al., 2017) as closely as possible. An advantage of this intentionally simple setup is that scalable NLP Transformer architectures – and their efficient implementations –…

AI 论文周报丨红队测试语言模型/多视角 3D 点追踪方法/蛋白质表示学习框架/密码学漏洞检测新框架……

近年来,已有若干方法尝试从单目视频实现 3D 点跟踪,然而由于在遮挡和复杂运动等挑战性场景中难以准确估计 3D 信息,这些方法的性能仍难以满足实际应用对高精度与鲁棒性的要求。 基于此,苏黎世联邦理工学院、卡内基梅隆大学联合提出…