设计模式和单一原则笔记

单一原则:方法 对象

策略模式:方法实现

// 策略接口(单一职责:定义计算规范)
public interface PriceStrategy {boolean match(String type);  // 职责1:判断是否适用该策略double calculate(double price); // 职责2:执行计算
}// 具体策略类(每个类只负责一种计算逻辑)
public class VipStrategy implements PriceStrategy {@Overridepublic boolean match(String type) {return "VIP".equals(type);}@Overridepublic double calculate(double price) {return price * 0.8;}
}public class FullReductionStrategy implements PriceStrategy {@Overridepublic boolean match(String type) {return "FULL_REDUCTION".equals(type);}@Overridepublic double calculate(double price) {return price > 100 ? price - 20 : price;}
}// 上下文类(单一职责:路由策略)
public class PriceContext {private List<PriceStrategy> strategies = new ArrayList<>();public PriceContext() {strategies.add(new VipStrategy());strategies.add(new FullReductionStrategy());}public double execute(String type, double price) {return strategies.stream().filter(s -> s.match(type)).findFirst().orElseThrow(() -> new IllegalArgumentException("未知价格策略")).calculate(price);}
}

** 使用工厂模式隔离对象创建**

// 创建逻辑单独封装
public class PaymentProcessorFactory {public PaymentProcessor create(String type) {if ("ALIPAY".equals(type)) return new AlipayProcessor();if ("WECHAT".equals(type)) return new WechatProcessor();throw new IllegalArgumentException("未知支付类型");}
}// 使用方保持单一职责
public class OrderService {private PaymentProcessorFactory factory;public void pay(Order order, String paymentType) {PaymentProcessor processor = factory.create(paymentType);processor.process(order.getAmount());}
}

通过装饰者模式叠加功能

// 基础接口
public interface DataReader {String read();
}// 基础实现(单一职责:读取数据)
public class FileDataReader implements DataReader {public String read() {// 读取文件内容...}
}// 装饰器1:增加缓存(单一职责:处理缓存)
public class CachedDataReader implements DataReader {private DataReader wrappee;private String cache;public CachedDataReader(DataReader reader) {this.wrappee = reader;}public String read() {if (cache == null) {cache = wrappee.read();}return cache;}
}// 装饰器2:增加解密(单一职责:数据解密)
public class DecryptDataReader implements DataReader {private DataReader wrappee;public DecryptDataReader(DataReader reader) {this.wrappee = reader;}public String read() {String data = wrappee.read();return decrypt(data);}
}// 使用组合
DataReader reader = new DecryptDataReader(new CachedDataReader(new FileDataReader()));

1 工厂方法模式(子类创建对象 接口屏蔽细节 支持新增产品)

抽象工厂1接口,具体工厂AB实现接口方法,
服务类 1 factory; if (…) {factory = new FactoryA();} factory调用方法

适用场景:需要创建对象但不确定具体类型时(如多数据源切换、协议适配)。
特点

  • 将对象创建延迟到子类
  • 通过接口屏蔽创建细节
  • 支持横向扩展(新增产品类型)

微服务应用示例:多数据库支持(MySQL/Oracle)

// 抽象工厂
public interface DataSourceFactory {DataSource createDataSource();
}// 具体工厂
public class MySQLDataSourceFactory implements DataSourceFactory {@Overridepublic DataSource createDataSource() {MysqlDataSource dataSource = new MysqlDataSource();dataSource.setURL("jdbc:mysql://localhost:3306/db");return dataSource;}
}public class OracleDataSourceFactory implements DataSourceFactory {@Overridepublic DataSource createDataSource() {OracleDataSource dataSource = new OracleDataSource();dataSource.setURL("jdbc:oracle:thin:@localhost:1521:xe");return dataSource;}
}// 使用工厂(通过环境变量切换)
public class DatabaseService {private DataSource dataSource;public DatabaseService() {String dbType = System.getenv("DB_TYPE");DataSourceFactory factory;if ("oracle".equalsIgnoreCase(dbType)) {factory = new OracleDataSourceFactory();} else {factory = new MySQLDataSourceFactory();}this.dataSource = factory.createDataSource();}
}

2 抽象工厂模式(定义抽象产品和工厂并实现,产品不能不太多)

创建工厂A 抽象产品BC 实现A和BC 选择工厂

1. 模式定义
抽象工厂模式是一种创建型设计模式,它提供一个接口用于创建相关或依赖对象的家族,而无需指定具体类。与工厂方法模式不同,抽象工厂关注的是产品族的创建。

核心思想:客户端代码只与抽象接口交互,完全不知道实际创建的具体产品是什么。

2. 模式结构
角色划分

角色说明示例代码
AbstractFactory(抽象工厂)声明创建产品族的方法GUIFactory
ConcreteFactory(具体工厂)实现具体产品的创建WindowsFactory/MacFactory
AbstractProduct(抽象产品)定义产品接口Button/Checkbox
ConcreteProduct(具体产品)实现具体产品类WindowsButton/MacCheckbox

UML类图
在这里插入图片描述

3. 代码示例:跨平台UI组件库

场景需求
开发一个支持Windows和Mac风格的UI库,需要创建:

  • 按钮(Button)
  • 复选框(Checkbox)

(1)抽象产品定义

// 抽象产品:按钮
public interface Button {void render();void onClick();
}// 抽象产品:复选框
public interface Checkbox {void paint();boolean isChecked();
}

(2)具体产品实现

// Windows风格组件
public class WindowsButton implements Button {@Overridepublic void render() {System.out.println("渲染Windows风格按钮");}@Overridepublic void onClick() {System.out.println("Windows按钮点击事件");}
}public class WindowsCheckbox implements Checkbox {@Overridepublic void paint() {System.out.println("绘制Windows风格复选框");}@Overridepublic boolean isChecked() {return true;}
}// Mac风格组件
public class MacButton implements Button {@Overridepublic void render() {System.out.println("渲染Mac风格按钮");}@Overridepublic void onClick() {System.out.println("Mac按钮点击事件");}
}public class MacCheckbox implements Checkbox {@Overridepublic void paint() {System.out.println("绘制Mac风格复选框");}@Overridepublic boolean isChecked() {return false;}
}

(3)抽象工厂定义

public interface GUIFactory {Button createButton();Checkbox createCheckbox();
}

(4)具体工厂实现

// Windows工厂
public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic Checkbox createCheckbox() {return new WindowsCheckbox();}
}// Mac工厂
public class MacFactory implements GUIFactory {@Overridepublic Button createButton() {return new MacButton();}@Overridepublic Checkbox createCheckbox() {return new MacCheckbox();}
}

(5)客户端代码

public class Application {private Button button;private Checkbox checkbox;public Application(GUIFactory factory) {this.button = factory.createButton();this.checkbox = factory.createCheckbox();}public void paint() {button.render();checkbox.paint();}public static void main(String[] args) {// 根据配置选择工厂GUIFactory factory;if (System.getProperty("os.name").contains("Windows")) {factory = new WindowsFactory();} else {factory = new MacFactory();}Application app = new Application(factory);app.paint();}
}

4. 模式优势

优点

  1. 确保产品兼容性:同一工厂创建的对象属于同一产品族
  2. 客户端与具体实现解耦:只依赖抽象接口
  3. 易于扩展新产品族:新增风格只需增加新工厂类

缺点

  1. 增加新产品类型困难:需要修改所有工厂接口(违反开闭原则)
  2. 类数量膨胀:每增加一个产品族需要新增多个类

5. 经典应用场景

  1. 跨平台UI框架(如Java AWT/Swing)
  2. 数据库访问层(支持多种数据库:MySQL/Oracle)
  3. 游戏开发(不同风格的角色/道具生成)
  4. 主题系统(白天/黑夜模式切换)

6. 模式对比
(1)抽象工厂 vs 工厂方法

维度抽象工厂工厂方法
关注点产品族创建单一产品创建
复杂度高(需要管理多个产品等级)
扩展方向横向扩展(新增产品族)纵向扩展(新增产品类型)
(2)抽象工厂 vs 建造者模式
  • 抽象工厂:立即返回组成产品族的各个对象
  • 建造者:分步骤构建复杂单一对象

7. Spring框架中的实践

Spring的FactoryBean接口与抽象工厂模式思想相似:

public interface FactoryBean<T> {T getObject() throws Exception;  // 相当于createProduct()Class<?> getObjectType();boolean isSingleton();
}// 使用示例
@Bean
public FactoryBean<DataSource> dataSource() {return new AbstractFactoryBean<DataSource>() {@Overridepublic Class<?> getObjectType() {return DataSource.class;}@Overrideprotected DataSource createInstance() {// 返回具体数据源实现return new HikariDataSource();}};
}

8. 最佳实践建议

  1. 合理控制产品族规模:避免一个工厂需要创建过多产品
  2. 考虑使用依赖注入(如Spring)来管理工厂实例
  3. 与原型模式结合:当产品创建成本高时,可以用原型减少new操作
  4. 明确产品族边界:不同产品族之间不应有隐含依赖

3 模板(代码少 父类掌握流程 有钩子)


抽象类 静态方法写步骤1234,拆分具体步骤,固定/抽象/钩子都行

经典案例
1. Java 集合框架
- AbstractListaddAll() 方法调用 add()(子类如 ArrayList 实现 add())。
2. Servlet 生命周期
- HttpServletservice() 方法调用 doGet()doPost()
3. Sp ring 框架
- JdbcTemplateexecute() 方法定义数据库操作流程,具体 SQL 由回调接口实现。

public abstract class AbstractClass {// 模板方法(final防止子类覆盖算法结构)public final void templateMethod() {step1();     // 固定步骤step2();     // 可变步骤(子类实现)if (hookMethod()) {  // 钩子方法(可选扩展点)step3();  }}// 固定实现(所有子类共用)private void step1() {System.out.println("执行固定步骤1");}// 抽象方法(必须由子类实现)protected abstract void step2();// 钩子方法(可选覆盖,提供默认实现)protected boolean hookMethod() {return true;}// 可选步骤(默认空实现)protected void step3() {}}

优势

  • 代码复用:公共逻辑集中在父类
  • 扩展可控:通过钩子方法提供灵活扩展点
  • 反向控制:父类掌控流程,子类专注实现

劣势

  • 继承强耦合:子类必须依赖父类
  • 违反开闭原则:新增步骤可能需要修改父类
  • 方法爆炸:过多抽象方法会增加子类负担

建议

  1. 模板方法尽量简短(不超过10行)
  2. 命名显式化
    • 模板方法用processXXX()/executeXXX()
    • 步骤方法用doXXX()/performXXX()
  3. 谨慎使用继承:如果变化点过多,考虑改用策略模式
  4. 合理使用钩子方法:避免过度设计,只在真正需要扩展点时使用

4 策略模式 (新增不用改旧代码 支付)

模式优势
优点
开闭原则:新增策略无需修改现有代码
消除条件语句:替代大量的if-else/switch-case
运行时灵活切换:动态改变对象行为
算法复用:不同上下文可共享策略对象

缺点
客户端必须了解所有策略:需要知道不同策略的区别
对象数量增加:每个策略都是一个类
通信开销:策略与上下文可能需要交换数据

经典应用场景
支付系统(如示例)
排序算法(快速排序/归并排序动态切换)
游戏AI(不同难度级别的敌人行为)
物流计算(不同快递公司的运费计算)
Spring资源访问Resource接口的不同实现)

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

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

相关文章

常见正则表达式整理与Java使用正则表达式的例子

一、常见正则表达式整理 1. 基础验证类 邮箱地址 ^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\\.[a-zA-Z]{2,}$ &#xff08;匹配如 userexample.com&#xff09;手机号 ^1[3-9]\\\\d{9}$ &#xff08;匹配国内11位手机号&#xff0c;如 13812345678&#xff09;中文字符 ^[\u4e00-\u9fa5…

vue2 项目的 vscode 插件整理

Folder Selector 当项目文件很多时&#xff0c;查找一个文件&#xff0c;可能需要在资源管理器中不断的滚动再打开文件夹查找文件&#xff0c;很麻烦&#xff0c;这个可以增加一个面板通过右键文件夹选择 然后在面板中查看文件 Reveal Button 文件中跳转到另一个文件时&#…

使用 Node、Express 和 MongoDB 构建一个项目工程

本文将详细介绍如何使用 Node.js Express MongoDB 构建一个完整的 RESTful API 后端项目&#xff0c;涵盖&#xff1a; 项目初始化 Express 服务器搭建 MongoDB 数据库连接 REST API 设计&#xff08;CRUD 操作&#xff09; 错误处理与中间件 源码结构与完整代码 部署建…

如何实现Spring Boot应用程序的安全性:全面指南

在现代 Web 开发中&#xff0c;安全性是 Spring Boot 应用程序的核心需求&#xff0c;尤其是在微服务、云原生和公开 API 场景中。Spring Boot 结合 Spring Security 提供了一套强大的工具&#xff0c;用于保护应用程序免受常见威胁&#xff0c;如未经授权的访问、数据泄露、跨…

无人机避障——Mid360+Fast-lio感知建图+Ego-planner运动规划(胎教级教程)

电脑配置:Xavier-nx、ubuntu 18.04、ros melodic 激光雷达:Livox_Mid-360 结果展示:左边Mid360+Fast-lio感知建图,右边Ego-planner运动规划 1、读取雷达数据并显示 无人机避障——感知篇(采用Livox-Mid360激光雷达获取点云数据显示)-CSDN博客 看看雷达数据话题imu以及…

数据库证书可以选OCP认证吗?

直接回答&#xff1a;国内OCP认证持有者的年薪普遍在15万到40万元之间&#xff0c;具体收入与经验、地区和行业强相关。OCP认证能大幅提升求职竞争力&#xff0c;但薪资天花板仍由个人能力决定。 一、薪资范围和核心影响因素 OCP认证是Oracle数据库领域的中高级“技术通行证”…

MySQL 从入门到精通:第二篇 - 数据类型、约束与索引

1. MySQL数据类型详解 数值类型 整数类型 -- 常用整数类型及范围 CREATE TABLE integer_types (tiny_col TINYINT, -- 1字节,有符号(-128~127),无符号(0~255)small_col SMALLINT, -- 2字节,有符号(-32768~32767),无符号(0~65535)medium_col MEDIUMINT,

Arduino 入门学习笔记(二):开发环境搭建

Arduino 入门学习笔记&#xff08;二&#xff09;&#xff1a;开发环境搭建 B站学习链接&#xff1a;link 1. Arduino IDE2软件介绍 Arduino IDE&#xff0c;Arduino Integrated Development Environment&#xff0c;即Arduino集成开发环境。 Arduino IDE具有程序编辑、调试…

ChatGPT、deepseek、豆包、Kimi、通义千问、腾讯元宝、文心一言、智谱清言代码能力对比

均使用测试时的最强模型 均是一次对话,对话内容一样 均开启深度思考 能联网的都联网了&#xff0c;但是作用不大&#xff0c;因为蓝桥杯刚考完&#xff0c;洛谷题目刚上传没多久 问题一测试了两遍 从问题三开始不再测试智谱清言&#xff08;它思考时间太长了&#xff0c;前两个…

OCR之身份证识别

前言 OCR身份证识别是光学字符识别技术在身份证领域的应用。通过扫描或拍照获取身份证图像&#xff0c;利用图像处理、深度学习等技术&#xff0c;自动提取姓名、性别、民族、出生日期、地址、身份证号等信息&#xff0c;可大幅提升信息录入效率&#xff0c;广泛应用于政务、金…

线性代数—向量与矩阵的范数(Norm)

参考链接&#xff1a; 范数&#xff08;Norm&#xff09;——定义、原理、分类、作用与应用 - 知乎 带你秒懂向量与矩阵的范数(Norm)_矩阵norm-CSDN博客 什么是范数&#xff08;norm&#xff09;&#xff1f;以及L1,L2范数的简单介绍_l1 norm-CSDN博客 范数&#xff08;Norm…

Java高频面试之并发编程-08

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;说说sleep和wait的区别&#xff1f; 1. 核心区别总结 特性sleep()wait()所属类Thread 类的静态方法Object 类的实例方法…

Spring-Ai-McpSever从外到内

MCP是什么 Model Context Protocol (MCP) 是一个开放协议&#xff0c;它使 LLM 应用与外部数据源和工具之间的无缝集成成为可能。无论你是构建 AI 驱动的 IDE、改善 chat 交互&#xff0c;还是构建自定义的 AI 工作流&#xff0c;MCP 提供了一种标准化的方式&#xff0c;将 LL…

ubuntu22.04 命令行修改静态ip

传统interfaces文件配置&#xff08;适用于旧版&#xff09;即便我们已经在桌面上配置了固定ip 这里也可以修改 ‌编辑配置文件‌ 修改/etc/network/interfaces&#xff08;需安装net-tools&#xff09;&#xff1a; # interfaces(5) file used by ifup(8) and ifdown(8) # In…

计算机网络学习笔记 4-6章

第 4 章 网络层 【考纲内容】 &#xff08;一&#xff09;网络层的功能 异构网络互连&#xff1b;路由与转发&#xff1b;SDN 基本概念&#xff1b;拥塞控制 &#xff08;二&#xff09;路由算法 静态路由与动态路由&#xff1b;距离 - 向量路由算法&#xff1…

力扣hot100_子串_python版本

一、560. 和为 K 的子数组 思路&#xff1a;这就是一道典型的前缀和的题代码: class Solution:def subarraySum(self, nums: List[int], k: int) -> int:presum [0] * (len(nums) 1)for i, x in enumerate(nums):presum[i 1] presum[i] x # 前缀和序列需要n1个ans 0…

猿人学web端爬虫攻防大赛赛题第15题——备周则意怠-常见则不疑

解题步骤 1、观察抓的包 2、有个m参数&#xff0c;一看就是经过处理的&#xff0c;我们得知道m是如何组成的。看Initiator模块。 3、还是看request函数&#xff0c;往上一看就看到了m的赋值操作。 打断点&#xff0c;触发。 4、看下window.m()的定义 5、比较好理解的&#x…

rag增强检索-基于关键词检索的混合检索模式

1. 为什么在 RAG 里要用关键词检索? 向量检索(embedding-based retrieval)是找语义相近的内容,但有时候不够准确。比如用户问了具体人名、产品型号、年份,这类关键词强指向性的信息,用向量检索可能匹配不到最相关内容。**关键词检索(keyword-based retrieval)**可以直接…

纯真社区IP库离线版发布更新

纯真社区IP库离线版发布更新 发布者&#xff1a;技术分享 2005年&#xff0c;随着中国互联网的蓬勃发展&#xff0c;纯真IP库诞生了。作为全球网络空间地理测绘技术的领先者&#xff0c;纯真开源项目为中国互联网行业提供了高质量的网络空间IP库数据。纯真IP库目前已经覆盖超…

GitOps进化:深入探讨 Argo CD 及其对持续部署的影响

什么是 GitOps&#xff1f; 虽然软件开发生命周期的大部分已经实现自动化&#xff0c;但基础设施仍然在很大程度上依赖于人工&#xff0c;需要专业团队的参与。随着当今基础设施需求的不断增长&#xff0c;实施基础设施自动化变得越来越重要。现代基础设施需要具备弹性&#x…