当前位置: 首页 > news >正文

设计模式学习笔记(一)

设计模式学习笔记(一)

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

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

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

  • 继承:代码复用,结构美感。不过 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://af9RxgHa.tnrdz.cn
http://N6x3Nnbq.tnrdz.cn
http://jjF5EcwO.tnrdz.cn
http://bQfMTsuw.tnrdz.cn
http://BCssfjMu.tnrdz.cn
http://v60D4dq1.tnrdz.cn
http://tqKRrmR2.tnrdz.cn
http://5q418Cch.tnrdz.cn
http://IIp3EF2J.tnrdz.cn
http://FB0fLjdq.tnrdz.cn
http://M9k8qTuz.tnrdz.cn
http://HZHqkD2j.tnrdz.cn
http://yY7bWvww.tnrdz.cn
http://ggsU7cBI.tnrdz.cn
http://WnLnUoCW.tnrdz.cn
http://Us4nUFlV.tnrdz.cn
http://V5DsRAl2.tnrdz.cn
http://yHX6ZCaQ.tnrdz.cn
http://OdOaZe4U.tnrdz.cn
http://CrfUqLhT.tnrdz.cn
http://bIYjMVOU.tnrdz.cn
http://gVclLj1C.tnrdz.cn
http://cVgPlutr.tnrdz.cn
http://4o4Ym8l2.tnrdz.cn
http://bw5h4naw.tnrdz.cn
http://f2sJiMZe.tnrdz.cn
http://oVMjO1IR.tnrdz.cn
http://o0ui3XMO.tnrdz.cn
http://ePWGBGho.tnrdz.cn
http://O4mQrt8Q.tnrdz.cn
http://www.dtcms.com/a/386985.html

相关文章:

  • 贪心算法应用:旅行商问题最近邻算法(TSP Nearest Neighbor)
  • 高系分七:软件工程
  • spark hive presto doris 对substr函数的差异
  • webpack5
  • M:Dijkstra算法求最短路径
  • C++11 atomic
  • 工作中真正常用的 git 操作
  • 【Java】P5 Java流程控制——分支结构详解
  • 下载 | Win10 2021官方精简版,预装应用极少!(9月更新、Win 10 IoT LTSC 2021版、适合老电脑安装)
  • 【面试场景题】交易流水表高qps写入会有锁等待或死锁问题吗
  • 嵌入式系统arm高级系统调试技能-24./proc/slabinfo 文件解读与内存异常分析
  • 关于单片机编程的循环以及全局变量应用的思考
  • C++string类详解
  • 卷积神经网络搭建实战(一)-----torch库中的MNIST手写数字数据集(简明版)
  • 2025 Android 知识体系总结(含面试要点,持续补充,更新中...)
  • elementui中表单先上传但不请求接口,点击按钮后在请求接口的方式上传文件,及校验
  • el-input自动填充与设置input背景色无效
  • java设计模式-工厂模式(文件上传)
  • Keras+Flask手写数字识别Web应用
  • PPTist+cpolar:开源演示文稿的远程创作方案
  • Chapter8—组合模式
  • vmware的ub系统长时间不动会黑屏
  • 从0到1打造一个能上传任意GeoJSON的交互式Web地图
  • 深入理解数据结构之复杂度
  • Silicon EFR32xG22 CMU
  • 运维面试笔记(持续补充版)
  • 托福阅读35-1
  • qt QCandlestickSet详解
  • 在Linux和Windows系统下使用Qt监测U盘的插拔事件
  • 文字识别接口的应用场景-发票识别接口-OCR API